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.
What you're building
Weather apps are one of the most popular beginner projects because they combine API fetching, data display, and responsive design. Open-Meteo provides a completely free weather API with no API key, making it the fastest path from zero to working app.
V0 generates the weather cards, search interface, and forecast layout from prompts. The Open-Meteo API returns current conditions, hourly forecasts, and 7-day predictions. Next.js ISR caching prevents repeated API calls for the same location, keeping responses fast and within rate limits.
The architecture uses an API route that calls Open-Meteo server-side (avoiding CORS), Server Components for the main weather display, and client components for the city search with autocomplete.
Final result
A weather app with city search, current conditions, hourly scroll, 7-day forecast cards, and optional saved locations.
Tech stack
Prerequisites
- 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
Build steps
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.
1import { NextRequest, NextResponse } from 'next/server'23export async function GET(req: NextRequest) {4 const lat = req.nextUrl.searchParams.get('lat')5 const lng = req.nextUrl.searchParams.get('lng')67 if (!lat || !lng) {8 return NextResponse.json(9 { error: 'lat and lng are required' },10 { status: 400 }11 )12 }1314 const params = new URLSearchParams({15 latitude: lat,16 longitude: lng,17 current: 'temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code',18 hourly: 'temperature_2m,precipitation_probability,weather_code',19 daily: 'temperature_2m_max,temperature_2m_min,weather_code,precipitation_sum',20 timezone: 'auto',21 forecast_days: '7',22 })2324 const res = await fetch(25 `https://api.open-meteo.com/v1/forecast?${params}`,26 { next: { revalidate: 1800 } }27 )2829 if (!res.ok) {30 return NextResponse.json(31 { error: 'Weather API error' },32 { status: 502 }33 )34 }3536 const data = await res.json()37 return NextResponse.json(data)38}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.
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.
1import { NextRequest, NextResponse } from 'next/server'23export async function GET(req: NextRequest) {4 const query = req.nextUrl.searchParams.get('q')56 if (!query || query.length < 2) {7 return NextResponse.json([])8 }910 const res = await fetch(11 `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(query)}&count=5&language=en`,12 { next: { revalidate: 86400 } }13 )1415 const data = await res.json()1617 const results = (data.results ?? []).map(18 (r: { name: string; country: string; latitude: number; longitude: number; admin1?: string }) => ({19 name: r.name,20 country: r.country,21 state: r.admin1,22 latitude: r.latitude,23 longitude: r.longitude,24 })25 )2627 return NextResponse.json(results)28}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.
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.
1// Paste this prompt into V0's AI chat:2// Build a weather dashboard at app/page.tsx with:3// 1. City search Input at the top using shadcn/ui Command for autocomplete (fetches from /api/geocode?q=query as user types, debounced 300ms)4// 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).5// 3. Horizontal ScrollArea showing hourly forecast for the next 24 hours — each hour shows time, small weather icon, and temperature6// 4. Grid of 7 Cards for the daily forecast: day name, weather icon, high/low temperatures, precipitation chance7// 5. Skeleton components for all sections while data loads8// 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)9// 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.
Add saved locations with Supabase (optional)
Optionally connect Supabase to save favorite locations. Users can toggle between saved cities using Tabs without re-searching.
1// Paste this prompt into V0's AI chat:2// Add saved locations to the weather app:3// 1. Connect Supabase via the Connect panel4// 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 timestamptz5// 3. Add a star/bookmark Button on the current weather Card to save the current location6// 4. Add shadcn/ui Tabs above the weather display showing saved locations. Clicking a tab loads that city's weather.7// 5. Server Action to save/remove locations and set default8// 6. On page load, fetch the user's default location (or New York if none saved)9// 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
1import { NextRequest, NextResponse } from 'next/server'23export async function GET(req: NextRequest) {4 const lat = req.nextUrl.searchParams.get('lat')5 const lng = req.nextUrl.searchParams.get('lng')67 if (!lat || !lng) {8 return NextResponse.json(9 { error: 'lat and lng are required' },10 { status: 400 }11 )12 }1314 const params = new URLSearchParams({15 latitude: lat,16 longitude: lng,17 current: 'temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code',18 hourly: 'temperature_2m,precipitation_probability,weather_code',19 daily: 'temperature_2m_max,temperature_2m_min,weather_code,precipitation_sum',20 timezone: 'auto',21 forecast_days: '7',22 })2324 const res = await fetch(25 `https://api.open-meteo.com/v1/forecast?${params}`,26 { next: { revalidate: 1800 } }27 )2829 if (!res.ok) {30 return NextResponse.json(31 { error: 'Weather API error' },32 { status: 502 }33 )34 }3536 const data = await res.json()37 return NextResponse.json(data)38}Customization ideas
Add weather alerts
Use Open-Meteo's alerts endpoint to show severe weather warnings. Display them as destructive Badge components at the top of the dashboard with Alert for detailed information.
Add temperature unit toggle
Add a Switch component to toggle between Celsius and Fahrenheit. Pass temperature_unit=fahrenheit to the Open-Meteo API or convert client-side.
Add weather maps
Integrate OpenStreetMap tiles with a weather overlay layer showing radar or precipitation maps using react-leaflet.
Add historical comparison
Use Open-Meteo's historical API to show how today's weather compares to the same date in previous years. Display as a comparison Card or Recharts line chart.
Common pitfalls
Pitfall: Calling the weather API directly from client-side components
How to avoid: 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.
Pitfall: Not debouncing the city search input
How to avoid: 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.
Pitfall: Hardcoding weather descriptions instead of mapping WMO codes
How to avoid: 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
AI prompts to try
Copy these prompts to build this project faster.
I'm building a weather app with Next.js App Router and the Open-Meteo API. I need: 1) An API route that fetches current conditions, hourly, and 7-day forecast with ISR caching (30 min revalidation), 2) A geocoding route for city name to coordinates lookup, 3) A mapping from WMO weather codes to icons and descriptions. Help me design the API layer and the weather code mapping.
Create a weather API route at app/api/weather/route.ts that calls Open-Meteo (api.open-meteo.com/v1/forecast) with lat/lng parameters, requests current weather (temperature, humidity, wind, weather_code), hourly forecast, and 7-day daily forecast. Use fetch with { next: { revalidate: 1800 } } for 30-minute ISR caching. Return 400 if lat/lng are missing, 502 if Open-Meteo returns an error.
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.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation