Next.js 2 min read 578 views

How to Build a Progressive Web App (PWA) with Next.js

Transform your Next.js application into a PWA with offline support, push notifications, and app-like experience.

E
PWA mobile app

Step 1: Install next-pwa

npm install next-pwa

Step 2: Configure next.config.js

const withPWA = require('next-pwa')({
    dest: 'public',
    register: true,
    skipWaiting: true,
    disable: process.env.NODE_ENV === 'development',
});

module.exports = withPWA({
    // your next config
});

Step 3: Create manifest.json

// public/manifest.json
{
    "name": "My Next.js App",
    "short_name": "NextApp",
    "description": "A Progressive Web App",
    "start_url": "/",
    "display": "standalone",
    "background_color": "#ffffff",
    "theme_color": "#1e40af",
    "icons": [
        {
            "src": "/icons/icon-192x192.png",
            "sizes": "192x192",
            "type": "image/png"
        },
        {
            "src": "/icons/icon-512x512.png",
            "sizes": "512x512",
            "type": "image/png"
        }
    ]
}

Step 4: Add Meta Tags

// app/layout.js or pages/_document.js
<Head>
    <link rel="manifest" href="/manifest.json" />
    <meta name="theme-color" content="#1e40af" />
    <link rel="apple-touch-icon" href="/icons/icon-192x192.png" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-status-bar-style" content="default" />
</Head>

Step 5: Install Prompt Component

'use client';

import { useEffect, useState } from 'react';

export function InstallPrompt() {
    const [installPrompt, setInstallPrompt] = useState(null);
    const [showPrompt, setShowPrompt] = useState(false);

    useEffect(() => {
        const handler = (e) => {
            e.preventDefault();
            setInstallPrompt(e);
            setShowPrompt(true);
        };

        window.addEventListener('beforeinstallprompt', handler);
        return () => window.removeEventListener('beforeinstallprompt', handler);
    }, []);

    const handleInstall = async () => {
        if (!installPrompt) return;

        installPrompt.prompt();
        const result = await installPrompt.userChoice;

        if (result.outcome === 'accepted') {
            setShowPrompt(false);
        }
    };

    if (!showPrompt) return null;

    return (
        <div className="fixed bottom-4 right-4 bg-white p-4 rounded-lg shadow-lg">
            <p>Install this app for a better experience!</p>
            <button onClick={handleInstall}>Install</button>
            <button onClick={() => setShowPrompt(false)}>Later</button>
        </div>
    );
}
Share this article:
ES

Written by Edrees Salih

Full-stack software engineer with 9 years of experience. Passionate about building scalable solutions and sharing knowledge with the developer community.

View Profile

Comments (0)

Leave a Comment

Your email will not be published.

No comments yet. Be the first to share your thoughts!