Skip to main content

Overview

NYC Permit Pulse is deployed on Vercel at permitpulse.nyc. Vercel handles:
  • Static hosting for the Vite build output
  • Server-side rewrites to proxy external API/tile requests
  • Custom domain with automatic HTTPS
  • Instant deployment on every git push

Vercel Configuration

The production rewrite rules are defined in vercel.json at the project root:
vercel.json
{
  "rewrites": [
    {
      "source": "/api/permits/:path*",
      "destination": "https://data.cityofnewyork.us/resource/rbx6-tga4.json/:path*"
    },
    {
      "source": "/api/jobs/:path*",
      "destination": "https://data.cityofnewyork.us/resource/w9ak-ipjd.json/:path*"
    },
    {
      "source": "/dzi/:path*",
      "destination": "https://isometric-nyc-tiles.cannoneyed.com/dzi/:path*"
    },
    {
      "source": "/api/adsb/:path*",
      "destination": "https://api.adsb.lol/v2/:path*"
    },
    {
      "source": "/map",
      "destination": "/index.html"
    },
    {
      "source": "/(.*)",
      "destination": "/index.html"
    }
  ]
}

How Rewrites Work

1

Browser makes a request

The app requests /api/permits?$where=... from the same origin (e.g., https://permitpulse.nyc/api/permits?$where=...).
2

Vercel rewrites the path

Before the request reaches the static files, Vercel’s edge network checks the rewrites rules and transforms the URL:
/api/permits?$where=... 
  → https://data.cityofnewyork.us/resource/rbx6-tga4.json?$where=...
3

Vercel proxies the request

Vercel fetches the data from NYC Open Data and returns it to the browser with the original domain (permitpulse.nyc), avoiding CORS errors.
The :path* syntax captures all remaining path segments and query parameters, allowing dynamic URLs like /api/permits?$where=issue_date>'2026-01-01' to pass through unchanged.

Rewrite Rules Breakdown

Source PathDestinationPurpose
/api/permits/:path*https://data.cityofnewyork.us/resource/rbx6-tga4.json/:path*DOB NOW approved work permits (Socrata ID: rbx6-tga4)
/api/jobs/:path*https://data.cityofnewyork.us/resource/w9ak-ipjd.json/:path*DOB NOW job filings for NB/DM (Socrata ID: w9ak-ipjd)
/dzi/:path*https://isometric-nyc-tiles.cannoneyed.com/dzi/:path*OpenSeadragon DZI descriptor + tile images
/api/adsb/:path*https://api.adsb.lol/v2/:path*Live helicopter tracking data
/map/index.htmlSPA route fallback for /map path
/(.*)/index.htmlCatch-all SPA route fallback
The order of rewrites matters! Specific paths (/api/permits, /dzi) must come before the catch-all /(.*) rule, or they’ll be overridden.

SPA Fallback

The last two rules handle client-side routing:
{
  "source": "/map",
  "destination": "/index.html"
},
{
  "source": "/(.*)",
  "destination": "/index.html"
}
This ensures that direct navigation to any path (e.g., permitpulse.nyc/map) returns index.html instead of a 404, allowing the React app to handle routing.

Deployment Process

1

Connect your GitHub repository

  1. Go to vercel.com/new
  2. Import your GitHub repository (e.g., yourusername/isometric-permits)
  3. Vercel auto-detects the Vite framework and suggests build settings
2

Configure build settings

Vercel should auto-detect these settings. Verify or set manually:
  • Framework Preset: Vite
  • Build Command: npm run build
  • Output Directory: dist
  • Install Command: npm install
These correspond to the scripts in package.json:6-10:
package.json
"scripts": {
  "dev": "vite",
  "build": "tsc -b && vite build",
  "preview": "vite preview"
}
3

Add vercel.json to your repository

Ensure vercel.json is committed to your repo root with the rewrite rules shown above.
git add vercel.json
git commit -m "Add Vercel rewrite configuration"
git push
4

Deploy

Click Deploy. Vercel will:
  1. Clone your repository
  2. Run npm install
  3. Run npm run build (TypeScript check + Vite build)
  4. Upload the dist/ folder to Vercel’s edge network
  5. Apply the vercel.json rewrites
You’ll get a deployment URL like: https://isometric-permits-abc123.vercel.app
5

Verify the deployment

  1. Visit the deployment URL
  2. Open browser DevTools → Network tab
  3. Check that /api/permits requests return 200 OK with JSON data
  4. Check that /dzi/nyc_files/*/ tile images load correctly
  5. Verify no CORS errors in the console

Custom Domain Setup

To deploy on a custom domain like permitpulse.nyc:
1

Add domain in Vercel

  1. Go to your project settings → Domains
  2. Click Add Domain
  3. Enter your domain (e.g., permitpulse.nyc)
2

Configure DNS records

Vercel will show you the required DNS records. For an apex domain (permitpulse.nyc):Option A: A Record (recommended)
Type: A
Name: @
Value: 76.76.19.19
Option B: CNAME (if your registrar supports apex CNAME)
Type: CNAME
Name: @
Value: cname.vercel-dns.com
For a subdomain (www.permitpulse.nyc):
Type: CNAME
Name: www
Value: cname.vercel-dns.com
3

Add both apex and www (optional)

It’s common to support both permitpulse.nyc and www.permitpulse.nyc:
  1. Add both domains in Vercel
  2. Set one as the primary (Vercel will redirect the other)
4

Wait for DNS propagation

DNS changes can take 5 minutes to 48 hours. Check status with:
dig permitpulse.nyc
You should see the Vercel IP address (76.76.19.19) in the response.
5

Vercel provisions SSL

Once DNS is verified, Vercel automatically provisions a free SSL certificate via Let’s Encrypt. Your site will be available at https://permitpulse.nyc.
Vercel automatically renews SSL certificates and handles HTTPS redirects. No manual configuration needed.

Environment Variables

NYC Permit Pulse does not require environment variables — all external URLs are handled via vercel.json rewrites. If you fork the project and need to add secrets:
1

Add environment variable in Vercel dashboard

Go to SettingsEnvironment Variables and add your key-value pairs:
VITE_API_KEY=your_secret_key
2

Access in code

Vite exposes env vars prefixed with VITE_:
const apiKey = import.meta.env.VITE_API_KEY
3

Redeploy

Environment variables are only injected during build. Push a new commit or manually trigger a redeploy.
Never commit .env files with secrets to git. Use Vercel’s environment variable UI instead.

Build Logs and Debugging

View Build Logs

  1. Go to your Vercel project → Deployments
  2. Click on a deployment
  3. View the Build Logs tab
You’ll see:
  • npm install output
  • TypeScript compilation (tsc -b)
  • Vite build output
  • Any errors that caused the build to fail

Common Build Errors

TypeScript errors
❌ error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
Fix: Run npm run build locally to catch type errors before pushing. Missing dependencies
❌ Module not found: Can't resolve 'openseadragon'
Fix: Ensure package.json includes all dependencies. Run npm install and commit the updated package-lock.json. Out of memory
❌ JavaScript heap out of memory
Fix: Rare for this project. If it happens, configure NODE_OPTIONS=--max_old_space_size=4096 in Vercel environment variables.

Runtime Debugging

If the build succeeds but the app doesn’t work:
  1. Check browser console for JavaScript errors
  2. Check Network tab for failed API/tile requests
  3. Verify rewrites are applied:
    curl -I https://permitpulse.nyc/api/permits?$limit=1
    
    Should return 200 OK with NYC Open Data headers.
  4. Check Vercel logs (real-time function logs): Go to DeploymentsFunctions tab (shows edge function errors if any)

Continuous Deployment

Vercel automatically deploys on every git push:
  • Main branch → Production deployment (permitpulse.nyc)
  • Other branches → Preview deployments (isometric-permits-git-feature-branch.vercel.app)
  • Pull requests → Preview deployments with automatic comments in the PR

Preview Deployments

Every PR gets a unique preview URL:
https://isometric-permits-git-add-helicopter-layer.vercel.app
Vercel posts a comment on the PR with the preview link. This lets you test changes before merging.

Skip a Deployment

To push without triggering a deployment, add [skip ci] to the commit message:
git commit -m "Update README [skip ci]"

Deployment Checklist

Before deploying to production:
  • Run npm run build locally to catch TypeScript errors
  • Run npm run preview and test the production build
  • Verify vercel.json includes all necessary rewrites
  • Commit and push vercel.json to the repo
  • Test API endpoints return valid data (check Network tab)
  • Test tile images load correctly (no 404s)
  • Check mobile responsiveness (DevTools device emulation)
  • Verify OpenSeadragon zoom and pan work smoothly

Production URL

The official deployment is live at: https://permitpulse.nyc Source code: github.com/ziggy2socks/isometric-permits

Next Steps

Build docs developers (and LLMs) love