Preflight scans your codebase before you deploy, and tells you what would embarrass you in production: the leaked key, the missing variable, the lapsed certificate, the page with no title.
One command, on your machine or in CI. Your code never leaves it and there is no account to make. It knows 72 services and every major framework and CMS. MIT licensed.
Homebrew
brew install preflightsh/preflight/preflight
npm
npm install -g @preflightsh/preflight
Go
go install github.com/preflightsh/preflight@latest
Docker
docker pull ghcr.io/preflightsh/preflight
curl
curl -sSL https://preflight.sh/install.sh | sh
Then, in your project: preflight init once, and preflight scan before every deploy.
Every check says OK, WARN or FAIL, and what to do about it.
This is a real scan of a small Next.js store with a few launch mistakes planted in it: a SendGrid key in the code, a webhook secret missing from .env, Sentry declared and never started, no favicon and no 404 page.
~/acme-store
preflight scan ✈ Preflight Scan Results
Project: acme-store
🔍 SEO SEO metadata ✓ OK · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
🔍 SEO Canonical URL ⚠ WARN
└─ No canonical URL tag found
• Add canonical to metadata: alternates: { canonical: 'https://...' }
• Or set metadataBase in root layout.tsx
· · · · · · · · · · · · · · · · · · · · · · · · · · · ·
📱 SOCIAL OG & Twitter cards configured ✓ OK · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
📱 MOBILE Viewport meta tag ✓ OK · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
🌐 LANG HTML lang attribute ✓ OK · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
🔍 SEO Structured data (JSON-LD) ⚠ WARN
└─ No structured data found
• Add JSON-LD script in layout: <script type="application/ld+json">{...}</script>
• Or use next-seo package for structured data
· · · · · · · · · · · · · · · · · · · · · · · · · · · ·
🔑 SECRETS Secrets scan ✗ FAIL
└─ Potential secrets found in 1 place(s)
• lib/mailer.ts:2 (SendGrid API key) [not gitignored]
• Remove secrets from source code
• Use environment variables instead
• Add sensitive files to .gitignore
• Consider using git-crypt or similar for encrypted secrets
· · · · · · · · · · · · · · · · · · · · · · · · · · · ·
📋 ENV Environment variables ⚠ WARN
└─ Missing in .env: STRIPE_WEBHOOK_SECRET
• Add STRIPE_WEBHOOK_SECRET to .env
· · · · · · · · · · · · · · · · · · · · · · · · · · · ·
📦 DEPS Dependency vulnerabilities ✓ OK · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
🐞 DEBUG Debug statements ⚠ WARN
└─ Found 1 debug statement(s)
• app/page.tsx:1 - console.log
· · · · · · · · · · · · · · · · · · · · · · · · · · · ·
📃 PAGES Error pages (404, 500) ⚠ WARN
└─ No custom 404 page found
• Create pages/404.tsx (Pages Router)
• Or create app/not-found.tsx (App Router)
· · · · · · · · · · · · · · · · · · · · · · · · · · · ·
⚡ PERF Image optimization ✓ OK · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
⚖️ LEGAL Privacy & Terms pages ⚠ WARN
└─ Missing: privacy policy, terms of service
• Add a privacy policy page (e.g., /privacy)
• Add terms of service page (e.g., /terms)
· · · · · · · · · · · · · · · · · · · · · · · · · · · ·
🎨 ICONS Favicon and app icons ✗ FAIL
└─ Missing favicon
• Add favicon.ico or favicon.png to public/
• Use https://realfavicongenerator.net for complete icon set
· · · · · · · · · · · · · · · · · · · · · · · · · · · ·
📄 FILES robots.txt ✓ OK · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
📄 FILES sitemap.xml ⚠ WARN
└─ sitemap.xml not found
• Add sitemap.xml to public/ directory
• Consider using next-sitemap or similar generator
· · · · · · · · · · · · · · · · · · · · · · · · · · · ·
📄 FILES llms.txt ⚠ WARN
└─ llms.txt not found
• Add llms.txt to help AI understand your site
• See https://llmstxt.org for specification
· · · · · · · · · · · · · · · · · · · · · · · · · · · · ──────────────────────────────────────────────────────── 🔌 Checked Services
🐛 ERRORS Sentry ⚠ WARN
└─ Sentry is declared but initialization not found
• Add Sentry.init() to your application entry point
• Check Sentry documentation for your framework
────────────────────────────────────────────────────────✓ Passed: 7 ⚠ Warnings: 9 ✗ Failed: 2 ✗ Not ready for launch
Captured from Preflight 0.22.0. The key is made up, and the report shows where a secret is, never the secret.
Why
Because everyone has shipped something broken.
A variable you forgot to set. Debug output left in. A certificate that lapsed over the weekend. A launch with no favicon and no privacy page. None of it is hard to fix; all of it is easy to miss when you are busy shipping.
Preflight is the “did I leave the stove on?” check for your codebase. Run it before you deploy, or put it in CI and stop thinking about it. No account, no dashboard to remember, and nothing to maintain beyond one preflight.yml.
Checks
What it looks for.
secretsAPI keys and credentials committed to the code, reported by file and line, never by value.
env_parityVariables your .env.example promises that .env doesn’t have.
security_headersHSTS, CSP and X-Content-Type-Options, on production and staging.
sslA valid certificate, with a warning well before it expires.
vulnerabilityKnown holes in your dependencies, through your package manager’s own audit.
debug_statementsconsole.log, var_dump and debugger left behind.
seo_metaA title, a description, Open Graph and Twitter cards, a canonical URL, JSON-LD.
error_pagesYour own 404 and 500 pages, not the framework’s.
legal_pagesA privacy policy and terms of service.
faviconA favicon, an apple-touch-icon and a web manifest.
robots_txtAnd the rest of the files a site should serve: sitemap.xml, llms.txt, ads.txt, humans.txt.
Preflight finds the services a project uses and checks each one is wired up: the key is in the environment, the SDK is started, the script is in the layout.
preflight init works out your stack, so each check knows which layout holds your <head>, where your public files live and which package manager to ask.
Put it in CI, and a pull request can’t ship a launch mistake.
A scan exits 2 when it finds an error and 1 on warnings only, so the step fails exactly when it should. Add --format json for something a script can read.
.github/workflows/ci.ymlGitHub Actions
- name: Run Preflight
run: |
curl -sSL https://preflight.sh/install.sh | sh
preflight scan --ci
With npm or Docker instead, and how to fail on errors only: the CI docs.
Agents
Or hand it to your coding agent.
Preflight ships an agent skill on skills.sh that teaches Claude Code, Cursor, Codex, OpenCode and more than 50 other agents to run a scan, fix what it finds without ignoring checks to get a pass, and scan again to prove it.
Then ask it, in plain words, whether the project is ready to launch. More in the agent skill docs.
Dashboard
Keep a history, and get a fix for every finding.
Add --publish and the run lands on your dashboard at app.preflight.sh, beside every run before it. Open any warning or failure for a step-by-step fix written for your stack. Only a redacted summary leaves your machine: check IDs, statuses and messages, never your code or a secret.
app.preflight.sh/r/acme-store
RunsSettingsBillingDocsLog out
preflight.sh
← All projects
acme-store · just now
acme-store is not ready for launch.
2 failed9 warnings7 passed
Copy all fixes as MarkdownDelete run
Failed
FAIL
Secrets scansecrets
Potential secrets found in 1 place(s)
Copy
AI fix suggestion
A SendGrid API key is hardcoded in lib/mailer.ts. Treat it as leaked: anyone with the repository can send mail as you.
Revoke the key in SendGrid under Settings, API Keys, and create a new one.
Put the new key in .env as SENDGRID_API_KEY, and add the name to .env.example.
Then rerun preflight scan --only secrets to confirm.
FAIL
Favicon and app iconsfavicon
Missing favicon
Copy
AI fix suggestion
The App Router picks up icons by file name, so no code is needed. Add these to app/:
app/favicon.ico, 32 by 32
app/icon.png, 512 by 512
app/apple-icon.png, 180 by 180
Next.js writes the <link> tags for each one.
Warnings
WARN
Canonical URLcanonical
No canonical URL tag found
Copy
AI fix suggestion
Writing a fix for your stack. This takes a few seconds the first time; after that it’s kept on the run.
WARN
Structured data (JSON-LD)structured_data
No structured data found
Copy
AI fix suggestion
Writing a fix for your stack. This takes a few seconds the first time; after that it’s kept on the run.
WARN
Environment variablesenv_parity
Missing in .env: STRIPE_WEBHOOK_SECRET
Copy
AI fix suggestion
Writing a fix for your stack. This takes a few seconds the first time; after that it’s kept on the run.
WARN
Sentrysentry
Sentry is declared but initialization not found
Copy
AI fix suggestion
Writing a fix for your stack. This takes a few seconds the first time; after that it’s kept on the run.
WARN
Debug statementsdebug_statements
Found 1 debug statement(s)
Copy
AI fix suggestion
Writing a fix for your stack. This takes a few seconds the first time; after that it’s kept on the run.
WARN
Error pages (404, 500)error_pages
No custom 404 page found
Copy
AI fix suggestion
Writing a fix for your stack. This takes a few seconds the first time; after that it’s kept on the run.
WARN
Privacy & Terms pageslegal_pages
Missing: privacy policy, terms of service
Copy
AI fix suggestion
Writing a fix for your stack. This takes a few seconds the first time; after that it’s kept on the run.
WARN
sitemap.xmlsitemap
sitemap.xml not found
Copy
AI fix suggestion
Writing a fix for your stack. This takes a few seconds the first time; after that it’s kept on the run.
WARN
llms.txtllms_txt
llms.txt not found
Copy
AI fix suggestion
Writing a fix for your stack. This takes a few seconds the first time; after that it’s kept on the run.
Passed
SEO metadata
OG & Twitter cards configured
Viewport meta tag
HTML lang attribute
Dependency vulnerabilities
Image optimization
robots.txt
The dashboard’s page for the scan above, drawn from its JSON with the app’s own markup; scroll inside it. The two fixes are examples of what the AI writes. Free for 5 published runs a month; unlimited with your own OpenAI or Anthropic key, or $5 a month with the AI on us. How it works.
Run it once before your next deploy, and find out what you missed.