Bill Pairaktaridis
Bill's Thoughts and Ramblings


Bill's Thoughts and Ramblings


A Step-by-Step Guide to Building a Full-Stack TypeScript Weather App with Node.js, React, and Tailwind CSS

Bill Pairaktaridis's photo
Bill Pairaktaridis
·Apr 9, 2023·

4 min read

Table of contents

  • Prerequisites:

In this guide, I will walk you through building a full-stack TypeScript weather app using Node.js, React, and Tailwind CSS. This app will fetch weather data from a third-party API, display the current weather, and provide a forecast for the next five days.


Before we begin, make sure you have the following installed on your system:

  1. Node.js and npm (latest LTS version recommended)

  2. A code editor like Visual Studio Code

  3. A basic understanding of TypeScript, React, and Node.js

Step 1: Set up the project structure

First, let's create a new folder for our project and navigate into it:

mkdir weather-app
cd weather-app

Next, create a client folder for the React app and a server folder for the Node.js server:

mkdir client server

Step 2: Set up the Node.js server

Navigate to the server folder and initialize a new Node.js project with TypeScript:

cd server
npm init -y
npm install typescript ts-node @types/node --save-dev
npx tsc --init

Edit the tsconfig.json file to enable the "esModuleInterop" option:

  "compilerOptions": {
    "esModuleInterop": true,

Install Express, Axios, and their respective types:

npm install express axios
npm install @types/express @types/axios --save-dev

Create a file named index.ts in the server folder and set up a basic Express server:

import express from 'express';

const app = express();
const PORT = process.env.PORT || 3001;

app.get('/', (req, res) => {
  res.send('Hello from the weather app server!');

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);

Add a start script to the server/package.json file:

"scripts": {
  "start": "ts-node index.ts"

Test the server by running npm start. You should see the message "Server is running on port 3001".

Step 3: Set up the React app

Navigate to the client folder and create a new React app using the create-react-app template:

cd ../client
npx create-react-app . --template typescript

Install the necessary dependencies:

npm install axios react-query tailwindcss@latest postcss@latest autoprefixer@latest

Initialize Tailwind CSS:

npx tailwindcss init

Add the following to your tailwind.config.js file:

module.exports = {
  purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
  darkMode: false,
  theme: {
    extend: {},
  variants: {
    extend: {},
  plugins: [],

Configure PostCSS by creating a postcss.config.js file in the client folder:

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},

Import the Tailwind CSS styles in the src/index.css file:

@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';

Step 4: Fetch and display weather data

Now, let's fetch the weather data from a third-party API, such as OpenWeatherMap. Sign up for a free account and get your API key.

In the server/index.ts file, add an endpoint to fetch weather data using Axios:

import axios from 'axios';

// Replace YOUR_API_KEY with your actual API key from OpenWeatherMap

app.get('/weather/:city', async (req, res) => {
  const city =;

  try {
    const response = await axios.get(
  } catch (error) {
    res.status(500).send('Error fetching weather data');

In the client/src folder, create a new file named useWeather.ts to fetch weather data using React Query:

import { useQuery } from 'react-query';
import axios from 'axios';

const fetchWeather = async (city: string) => {
  const response = await axios.get(`/weather/${city}`);

export const useWeather = (city: string) => {
  return useQuery(['weather', city], () => fetchWeather(city));

Create a new WeatherCard.tsx component to display the weather data:

import React from 'react';

interface WeatherCardProps {
  weatherData: any;

const WeatherCard: React.FC<WeatherCardProps> = ({ weatherData }) => {
  return (
    <div className="bg-white p-6 rounded-md shadow-md">
      <h2 className="text-xl font-bold">
        {}, {}
      <p className="text-gray-600">{[0].description}</p>
      <p className="text-4xl font-bold">

export default WeatherCard;

Now, update the src/App.tsx file to fetch and display the weather data using the useWeather hook and WeatherCard component:

import React, { useState } from 'react';
import './App.css';
import WeatherCard from './WeatherCard';
import { useWeather } from './useWeather';

function App() {
  const [city, setCity] = useState('London');
  const { data, isLoading, isError } = useWeather(city);

  const handleSearch = () => {
    // Add your search logic here

  return (
    <div className="App">
      <header className="App-header">
        <h1>Weather App</h1>
          placeholder="Search by city"
          onChange={(e) => setCity(}
        <button onClick={handleSearch}>Search</button>
        {isLoading && <p>Loading...</p>}
        {isError && <p>Error fetching weather data</p>}
        {data && <WeatherCard weatherData={data} />}

export default App;

You now have a basic full-stack TypeScript weather app using Node.js, React, and Tailwind CSS. You can expand this app by adding a five-day forecast, error handling, and user input validation.

What would you add or change? Sign off in the comments!

Share this