Documentation
Next.js

Next.js

Install and configure Next.js as a PWA

Automatic Install

npx pwawtf next-app

Manual Install

Initialize project

Create a new Next.js project with create-next-app:

npx create-next-app@latest my-app --typescript --tailwind

Install @ducanh2912/next-pwa

Once your Next.js project has been initialized, install @ducanh2912/next-pwa:

npm i @ducanh2912/next-pwa

Configure @ducanh2912/next-pwa

Open up your next.config.js file:

my-app/
├── public/
├── ...
├── next.config.js <- open 
├── ...
└── tsconfig.json

And add the following:

// <rootDir>/next.config.js
const withPwa = require('@ducanh2912/next-pwa').default({ 
  dest: 'public' 
}) 
 
/** @type {import('next').NextConfig} */
const nextConfig = {}
 
module.exports = nextConfig 
module.exports = withPwa(nextConfig) 

Add a Manifest File

Create a manifest.json file in your public folder:

my-app/
├── public/
│   └── manifest.json 
├── src/
├── ...
└── tsconfig.json

And fill it with:

// <rootDir>/public/manifest.json
{
  "name": "My App",
  "short_name": "My App",
  "icons": [],
  "theme_color": "#FFFFFF",
  "background_color": "#FFFFFF",
  "start_url": "/",
  "display": "standalone",
  "orientation": "portrait"
}

Add Icons

You will need to add 32x32, 192x192 and 512x512 resolution icons to your public folder:

my-app/
├── public/
│   ├── icon@32x32.png 
│   ├── icon@192x192.png 
│   ├── icon@512x512.png 
│   └── manifest.json
├── src/
├── .gitignore
├── next-env.d.ts
├── next.config.js
├── package.json
├── README.md
└── tsconfig.json

If you don't have these handy yet, you can use ours as a placeholder for now:

32x32192x192512x512
32x32192x192512x512

Download

Add Maskable Icon

Next, we will need to add a maskable icon (opens in a new tab) to adapt to different shapes.

We can take our icon@512x512.png icon and run it through Maskable.app Editor (opens in a new tab) to generate a maskable icon.

If you don't want to do this now, you can use the maskable icon in the Download zip file we gave you.

Add the 512x512 maskable icon to your public folder:

my-app/
├── public/
│   ├── icon@32x32.png
│   ├── icon@192x192.png
│   ├── icon@512x512.png
|   ├── icon-maskable@512x512.png 
│   └── manifest.json
├── src/
├── .gitignore
├── next-env.d.ts
├── next.config.js
├── package.json
├── README.md
└── tsconfig.json

Add Icons to manifest.json

Now that we have our icons, we can add them to our manifest.json file:

// <rootDir>/public/manifest.json
{
  "name": "My App",
  "short_name": "My App",
  "icons": [
    { 
      "src": "icon@32x32.png", 
      "type": "image/png", 
      "sizes": "32x32" 
    }, 
    { 
      "src": "icon@192x192.png", 
      "type": "image/png", 
      "sizes": "192x192" 
    }, 
    { 
      "src": "icon@512x512.png", 
      "type": "image/png", 
      "sizes": "512x512" 
    }, 
    { 
      "src": "icon-maskable@512x512.png", 
      "type": "image/png", 
      "sizes": "512x512", 
      "purpose": "maskable" 
    }, 
  ],
  "theme_color": "#FFFFFF",
  "background_color": "#FFFFFF",
  "start_url": "/",
  "display": "standalone",
  "orientation": "portrait"
}

Add <meta> tags to layout.tsx

Open the root layout.tsx file:

my-app/
├── public/
├── src/
│   └── app/
│       └── layout.tsx <- open 
├── ...
└── tsconfig.json

And add the following:

// <rootDir>/src/app/layout.tsx
import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
 
const inter = Inter({ subsets: ['latin'] })
 
export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
  manifest: '/manifest.json', 
  icons: [ 
    { 
      url: '/icon@32x32.png', 
      sizes: '32x32', 
      type: 'image/png', 
      rel: 'icon', 
    }, 
    { 
      url: '/icon@192x192.png', 
      sizes: '192x192', 
      type: 'image/png', 
      rel: 'icon', 
    }, 
    { 
      url: '/icon@512x512.png', 
      sizes: '512x512', 
      type: 'image/png', 
      rel: 'icon', 
    } 
  ], 
  themeColor: '#FFFFFF', 
  viewport: 'width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no', 
}
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  )
}

Check your work

To make sure we've set everything up correctly, let's run a Lighthouse audit.

  1. Run npm run dev to start your Next.js App
  2. Open up your Chromium browser and navigate to http://localhost:3000
  3. Open up DevTools and go to the Lighthouse tab
  4. Click Progressive Web App under Categories
  5. Press the Analyze page load button to run the audit.

After auditing, you should see a score of 100 for PWA.

Lighthouse Audit

Links