# How to Build Weather application with V0

- Tool: v0
- Difficulty: Beginner
- Compatibility: V0 Free
- Last updated: April 2026

## TL;DR

Build a weather app with V0 featuring current conditions and 7-day forecast cards using the free Open-Meteo API (no API key required), city search with autocomplete, and ISR caching with 30-minute revalidation. You'll create responsive weather cards with shadcn/ui, hourly scroll, and saved locations — all in about 30-60 minutes.

## Before you start

- A V0 account (free tier works perfectly for this project)
- No API keys needed — Open-Meteo is completely free with no signup
- Optional: a Supabase project for saving favorite locations

## Step-by-step guide

### 1. Create the weather API route with ISR caching

Build a server-side API route that calls Open-Meteo with latitude and longitude coordinates. Use Next.js fetch caching with revalidation to cache responses for 30 minutes, preventing unnecessary API calls.

```
import { NextRequest, NextResponse } from 'next/server'

export async function GET(req: NextRequest) {
  const lat = req.nextUrl.searchParams.get('lat')
  const lng = req.nextUrl.searchParams.get('lng')

  if (!lat || !lng) {
    return NextResponse.json(
      { error: 'lat and lng are required' },
      { status: 400 }
    )
  }

  const params = new URLSearchParams({
    latitude: lat,
    longitude: lng,
    current: 'temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code',
    hourly: 'temperature_2m,precipitation_probability,weather_code',
    daily: 'temperature_2m_max,temperature_2m_min,weather_code,precipitation_sum',
    timezone: 'auto',
    forecast_days: '7',
  })

  const res = await fetch(
    `https://api.open-meteo.com/v1/forecast?${params}`,
    { next: { revalidate: 1800 } }
  )

  if (!res.ok) {
    return NextResponse.json(
      { error: 'Weather API error' },
      { status: 502 }
    )
  }

  const data = await res.json()
  return NextResponse.json(data)
}
```

> Pro tip: The { next: { revalidate: 1800 } } option caches the Open-Meteo response for 30 minutes. Repeat requests for the same coordinates return instantly from the cache without hitting the external API.

**Expected result:** The API route returns current conditions, hourly forecasts, and 7-day predictions for any coordinates. Responses are cached for 30 minutes via ISR.

### 2. Create the geocoding API for city search

Build a second API route that converts city names to coordinates using Open-Meteo's free geocoding endpoint. This powers the city search autocomplete.

```
import { NextRequest, NextResponse } from 'next/server'

export async function GET(req: NextRequest) {
  const query = req.nextUrl.searchParams.get('q')

  if (!query || query.length < 2) {
    return NextResponse.json([])
  }

  const res = await fetch(
    `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(query)}&count=5&language=en`,
    { next: { revalidate: 86400 } }
  )

  const data = await res.json()

  const results = (data.results ?? []).map(
    (r: { name: string; country: string; latitude: number; longitude: number; admin1?: string }) => ({
      name: r.name,
      country: r.country,
      state: r.admin1,
      latitude: r.latitude,
      longitude: r.longitude,
    })
  )

  return NextResponse.json(results)
}
```

> Pro tip: Cache geocoding results for 24 hours (86400 seconds) since city coordinates do not change. This dramatically reduces API calls during development when you search the same cities repeatedly.

**Expected result:** Searching for 'New York' returns a list of matching cities with their coordinates, country, and state/region for disambiguation.

### 3. Build the weather dashboard with current conditions and forecast

Create the main page with the current weather Card, hourly ScrollArea, and 7-day forecast grid. Use V0's Design Mode to customize the card layout and color gradients.

```
// Paste this prompt into V0's AI chat:
// Build a weather dashboard at app/page.tsx with:
// 1. City search Input at the top using shadcn/ui Command for autocomplete (fetches from /api/geocode?q=query as user types, debounced 300ms)
// 2. Current conditions Card: large temperature number, weather description, humidity, wind speed, feels-like temperature. Use a gradient background based on temperature (blue for cold, warm tones for hot).
// 3. Horizontal ScrollArea showing hourly forecast for the next 24 hours — each hour shows time, small weather icon, and temperature
// 4. Grid of 7 Cards for the daily forecast: day name, weather icon, high/low temperatures, precipitation chance
// 5. Skeleton components for all sections while data loads
// 6. Map WMO weather codes to icons and descriptions (0=Clear, 1-3=Partly Cloudy, 45-48=Fog, 51-55=Drizzle, 61-65=Rain, 71-77=Snow, 80-82=Showers, 95-99=Thunderstorm)
// Fetch weather from /api/weather?lat=X&lng=Y. Default to New York (40.71, -74.01).
```

> Pro tip: Use V0's Design Mode (Option+D) to visually adjust the weather card gradients, icon sizes, and typography at zero credit cost. This is where weather apps really shine.

**Expected result:** A weather dashboard showing current conditions in a gradient Card, a horizontal hourly scroll, and a 7-day forecast grid with weather icons and temperatures.

### 4. Add saved locations with Supabase (optional)

Optionally connect Supabase to save favorite locations. Users can toggle between saved cities using Tabs without re-searching.

```
// Paste this prompt into V0's AI chat:
// Add saved locations to the weather app:
// 1. Connect Supabase via the Connect panel
// 2. Create a saved_locations table: id uuid PK, user_id uuid, city text, country text, latitude numeric, longitude numeric, is_default boolean DEFAULT false, created_at timestamptz
// 3. Add a star/bookmark Button on the current weather Card to save the current location
// 4. Add shadcn/ui Tabs above the weather display showing saved locations. Clicking a tab loads that city's weather.
// 5. Server Action to save/remove locations and set default
// 6. On page load, fetch the user's default location (or New York if none saved)
// RLS: users can only read/write their own saved locations.
```

**Expected result:** Users can save favorite cities and switch between them using Tabs. The default location loads automatically on page visit.

## Complete code example

File: `app/api/weather/route.ts`

```typescript
import { NextRequest, NextResponse } from 'next/server'

export async function GET(req: NextRequest) {
  const lat = req.nextUrl.searchParams.get('lat')
  const lng = req.nextUrl.searchParams.get('lng')

  if (!lat || !lng) {
    return NextResponse.json(
      { error: 'lat and lng are required' },
      { status: 400 }
    )
  }

  const params = new URLSearchParams({
    latitude: lat,
    longitude: lng,
    current: 'temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code',
    hourly: 'temperature_2m,precipitation_probability,weather_code',
    daily: 'temperature_2m_max,temperature_2m_min,weather_code,precipitation_sum',
    timezone: 'auto',
    forecast_days: '7',
  })

  const res = await fetch(
    `https://api.open-meteo.com/v1/forecast?${params}`,
    { next: { revalidate: 1800 } }
  )

  if (!res.ok) {
    return NextResponse.json(
      { error: 'Weather API error' },
      { status: 502 }
    )
  }

  const data = await res.json()
  return NextResponse.json(data)
}
```

## Common mistakes

- **Calling the weather API directly from client-side components** — While Open-Meteo allows CORS, calling from the client means every user triggers a fresh API request on every page load. You lose ISR caching benefits and risk hitting rate limits. Fix: Route all weather requests through your API route (/api/weather) where Next.js fetch caching with { next: { revalidate: 1800 } } caches responses server-side for 30 minutes.
- **Not debouncing the city search input** — Without debouncing, every keystroke triggers a geocoding API request. Typing 'New York' sends 8 requests instead of 1. Fix: Debounce the search input by 300ms. Only fire the geocoding request after the user stops typing. Use a simple setTimeout/clearTimeout pattern or a useDebounce hook.
- **Hardcoding weather descriptions instead of mapping WMO codes** — Open-Meteo returns WMO weather codes (integers), not human-readable descriptions. Displaying the raw number (e.g., '61') means nothing to users. Fix: Create a mapping object from WMO codes to descriptions and icons: 0=Clear sky, 1-3=Partly cloudy, 51-55=Drizzle, 61-65=Rain, 71-77=Snow, 95-99=Thunderstorm.

## Best practices

- Use Open-Meteo for weather data — it is completely free, requires no API key, and has no signup process
- Cache weather responses with { next: { revalidate: 1800 } } (30 minutes) to prevent redundant API calls
- Cache geocoding responses with { next: { revalidate: 86400 } } (24 hours) since city coordinates never change
- Debounce city search input by 300ms to avoid excessive geocoding API calls on every keystroke
- Map WMO weather codes to icons and descriptions using a static lookup object
- Use V0's Design Mode (Option+D) to visually polish weather cards with temperature-based gradients at zero credit cost
- Add Skeleton loading states for all weather sections to prevent layout shift during data fetching

## Frequently asked questions

### Does Open-Meteo require an API key?

No. Open-Meteo is completely free for non-commercial use with no signup, no API key, and no rate limit registration. For commercial use, they offer an API key option at $15/month with higher rate limits.

### What are WMO weather codes?

WMO (World Meteorological Organization) codes are integer values representing weather conditions. Open-Meteo returns these instead of text descriptions. You need to map them: 0=Clear, 1-3=Partly Cloudy, 45-48=Fog, 51-55=Drizzle, 61-65=Rain, 71-77=Snow, 80-82=Showers, 95-99=Thunderstorm.

### Why fetch weather server-side instead of from the client?

Server-side fetching enables ISR caching. When two users check weather for the same city within 30 minutes, the second request is served from cache instantly. Client-side fetching would hit the API on every page load for every user.

### What V0 plan do I need?

V0 Free tier works perfectly. The weather app is a simple project with Server Components, two API routes, and shadcn/ui components. No paid integrations are required since Open-Meteo is free.

### Can I use OpenWeatherMap instead?

Yes. Replace the Open-Meteo API calls with OpenWeatherMap endpoints and add your OPENWEATHER_API_KEY in V0's Vars tab (no NEXT_PUBLIC_ prefix since it is used server-side). The response format differs, so you will need to adjust the data mapping.

### How do I deploy this?

Click Share then Publish in V0. No environment variables are needed if using Open-Meteo. If you added Supabase for saved locations, the connection is auto-configured via the Connect panel.

### Can RapidDev help build a custom weather or location-based app?

Yes. RapidDev has built 600+ apps including location-based services with real-time data integration, maps, and custom dashboards. Book a free consultation to discuss your project requirements.

---

Source: https://www.rapidevelopers.com/how-to-build-v0/weather-application
© RapidDev — https://www.rapidevelopers.com/how-to-build-v0/weather-application
