javascript
59 lines · 9 steps
Generating a PWA manifest and icon in Next.js
A single file exports a web app manifest plus a dynamically rendered PNG icon using Next.js metadata conventions.
Explained by
highlit
1import { ImageResponse } from 'next/og'
2
3export function manifest() {
4 return {
5 name: 'Acme Analytics Dashboard',
6 short_name: 'Acme',
7 description: 'Real-time metrics and reporting for your team.',
8 start_url: '/',
9 scope: '/',
10 display: 'standalone',
11 orientation: 'portrait',
12 background_color: '#0f172a',
13 theme_color: '#6366f1',
14 categories: ['business', 'productivity'],
15 icons: [
16 {
17 src: '/icon',
18 sizes: '512x512',
19 type: 'image/png',
20 purpose: 'any',
21 },
22 {
23 src: '/apple-icon',
24 sizes: '180x180',
25 type: 'image/png',
26 purpose: 'maskable',
27 },
28 ],
29 }
30}
31
32export const size = { width: 512, height: 512 }
33export const contentType = 'image/png'
34
35export function icon() {
36 return new ImageResponse(
37 (
38 <div
39 style={{
40 width: '100%',
41 height: '100%',
42 display: 'flex',
43 alignItems: 'center',
44 justifyContent: 'center',
45 background: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
46 color: '#fff',
47 fontSize: 320,
48 fontWeight: 700,
49 borderRadius: 96,
50 }}
51 >
52 A
53 </div>
54 ),
55 { ...size }
56 )
57}
58
59export default manifest
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Next.js turns exported functions and constants in special files into generated static assets at build time.
- 2A manifest describes install behavior while its icons array points at routes that themselves produce images.
- 3ImageResponse renders JSX to a raster image on the server, so no design tool is needed for simple icons.
Related explainers
javascript
const ROLE_PERMISSIONS = { admin: ['users:read', 'users:write', 'billing:read', 'billing:write'], manager: ['users:read', 'billing:read'], member: ['users:read'],
Role-based permissions middleware in Express
authorization
middleware
rbac
Intermediate
9 steps
javascript
function attachThousandSeparators(input, { locale = 'en-US' } = {}) { const formatter = new Intl.NumberFormat(locale); const groupSep = formatter.format(11111).replace(/\d/g, '')[0] || ','; const decimalSep = formatter.format(1.1).replace(/\d/g, '')[0] || '.';
Live thousand separators without losing the caret
dom
intl
caret-preservation
Advanced
8 steps
javascript
import { useReducer, useEffect } from "react"; const initialState = { status: "idle", data: null, error: null };
Building a data-fetching hook in React
custom-hooks
usereducer
data-fetching
Intermediate
9 steps
javascript
const express = require('express'); const app = express(); app.get('/health', (req, res) => res.json({ status: 'ok' }));
Graceful shutdown in an Express server
graceful-shutdown
signal-handling
connection-tracking
Advanced
9 steps
javascript
import { useState, useEffect, useCallback } from 'react'; function getColumnCount(width) { if (width < 640) return 1;
A responsive column hook in React
custom-hooks
debouncing
responsive-design
Intermediate
7 steps
typescript
import { CanActivate, ExecutionContext, Injectable,
Role-based access with a NestJS guard
authorization
guards
decorators
Intermediate
6 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/generating-a-pwa-manifest-and-icon-in-next-js-explained-javascript-23a8/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.