---
title: Going to production checklist
layout: docs
nav: apps
redirect_from:
- /docs/going-to-production/
- /docs/going-to-production/the-basics/
- /docs/going-to-production/the-basics/production-databases/
- /docs/reference/going-to-production/
---
Use this checklist to help you set up a production environment on Fly.io.
<figure class="flex justify-center">
<img src="/static/images/outlook.png" alt="Illustration by Annie Ruygt of Frankie the hot air balloon waving to a bird sitting on a hour roof" class="max-w-lg">
</figure>
## Overview
Moving an app from staging to production can expose unexpected failure modes: security holes, performance and scaling issues, or data loss. This checklist is meant to catch common pitfalls for apps on Fly.io, but it’s not a guarantee of production readiness. Not every item here will apply to your app, and you may have additional requirements that aren't listed. Use this as a foundation and adapt it to your needs. Think of this list as a scaffold, not a silver bullet.
<div class="important icon">
**Important:** The checklist is not exhaustive and does not guarantee production-readiness for your app. Apps can have unique requirements for production depending on the framework and type of app. Some items won't be applicable and there may be other considerations not listed here; you'll need to decide which checklist items work for your app.
</div>
## Security
<%= render ChecklistComponent.new(
items: [
{ id: "sso", title: "Set up single sign-on for organizations", description: "Enable SSO on your organization to take advantage of Google or GitHub authentication security. Learn more about [Single sign-on for organizations](/docs/security/sso/)." },
{ id: "isolation", title: "Isolate staging and production environments", description: "Use organizations to limit access to your production environment. Read this guide: [Staging and production isolation](/docs/blueprints/staging-prod-isolation/)." },
{ id: "least-privilege", title: "Enforce least privilege access", description: "Use access tokens to allow only the minimum access level required by team members to your organization, apps, and Machines. Understand [access tokens](https://fly.io/docs/security/tokens/)." },
{ id: "secrets", title: "Protect sensitive information", description: "Set secrets to store sensitive data and make them available as environment variables to your app. Read about [Secrets and Fly Apps](/docs/apps/secrets/)." },
{ id: "exposure", title: "Make sure private services are not exposed", description: "Check that your private apps with services don't have public IP addresses. Run `fly ips list` and use `fly ips release` to release unnecessary public IPs. More detail is available in this `flyctl` reference: [`fly ips` commands](/docs/flyctl/ips/). Assign private apps a [Flycast address](https://fly.io/docs/networking/flycast/) instead." },
{ id: "arcjet", title: "Use Arcjet application security for JavaScript apps", description: "Secure your app with rate limiting, bot protection, email validation, and defense against common attacks through our extension partner Arcjet. Read more about [Application Security by Arcjet](/docs/security/arcjet/)." }
],
c: params[:c] || "",
o: params[:o] || "",
h: params[:h] || ""
) %>
## Databases
<%= render ChecklistComponent.new(
items: [
{ id: "production-grade-postgres", title: "Use Managed Postgres", description: "We recommend using [Fly.io's Managed Postgres](/docs/mpg/), our fully-managed database service that handles all aspects of running production PostgreSQL."},
{ id: "test-backups", title: "Practice your disaster recovery plan", description: "Practice restoring your managed Postgres database from a backup before you actually need to. You can do this anytime from the Managed Postgres dashboard." }
],
c: params[:c] || "",
o: params[:o] || "",
h: params[:h] || ""
) %>
## App performance
<%= render ChecklistComponent.new(
items: [
{ id: "machine-sizing", title: "Get Machine sizing right", description: "Most conventional production web apps require [performance CPUs](/docs/machines/cpu-performance/). Also make sure you have enough RAM for your app and/or enable [swapping to disk](/docs/reference/configuration/#swap_size_mb-option) to deal with brief spikes in memory use. Find out more details in our [Machine sizing guide](/docs/machines/guides-examples/machine-sizing/)."},
{ id: "fine-tune-app", title: "Fine-tune your app", description: "Learn about optimizing your app on Fly.io. Read these tips to [fine-tune your app on Fly.io](/docs/apps/fine-tune-apps/)."}
],
c: params[:c] || "",
o: params[:o] || "",
h: params[:h] || ""
) %>
## Availability, resiliency, and costs
<%= render ChecklistComponent.new(
items: [
{ id: "multiple-machines", title: "Use multiple Machines for resiliency", description: "Make your app resilient to single-host failures with multiple Machines that stay stopped until you need them. Learn more in our guide: [Resilient apps use multiple Machines](/docs/blueprints/resilient-apps-multiple-machines/)."},
{ id: "add-regions", title: "Scale your app into more regions", description: "Scale your app in multiple regions closest to your app's users. Find out how to [Scale an app's regions](/docs/launch/scale-count/#scale-an-apps-regions)."},
{ id: "autostop-autostart", title: "Use autostop/autostart to reduce costs", description: "Autostop/autostart lets you stop or suspend Machines when there's low traffic, saving on resource usage and costs. You get autostop/autostart by default with a new app, but you can configure it to optimize for your use case. Find out more: [Autostop/autostart Machines](/docs/launch/autostop-autostart/)."},
{ id: "autoscale-by-metric", title: "Set up autoscaling by metric to reduce costs", description: "For apps that aren't running web services, use the autoscaler app to scale your app's Machines based on any metric, saving on resource usage and costs. Learn how to [Autoscale based on metrics](/docs/launch/autoscale-by-metric/)."}
],
c: params[:c] || "",
o: params[:o] || "",
h: params[:h] || ""
) %>
## Networking
<%= render ChecklistComponent.new(
items: [
{ id: "custom-domain", title: "Set up a custom domain", description: "Configure a certificate for your domain. Learn how to [use a custom domain](/docs/networking/custom-domain/)."},
{ id: "ipv4", title: "Consider using a dedicated IPv4 address", description: "Completely eliminate the chance of blacklisted spammers causing problems for your app. There is a small [added cost](/docs/about/pricing/#anycast-ip-addresses) for dedicated IPv4 addresses. Read more about [Dedicated IPv4](/docs/networking/services/#dedicated-ipv4)."},
{ id: "flycast", title: "Set up Flycast for private apps", description: "If you haven't already done so, give your private apps a Flycast address to communicate with them entirely on your private network. Find out about [Flycast - Private Fly Proxy services](https://fly.io/docs/networking/flycast/)."}
],
c: params[:c] || "",
o: params[:o] || "",
h: params[:h] || ""
) %>
## Monitoring
<%= render ChecklistComponent.new(
items: [
{ id: "metrics", title: "Monitor your app with fully-managed metrics", description: "Use managed Prometheus and managed Grafana dashboards to monitor your app. Read about [Metrics on Fly.io](/docs/monitoring/metrics/)."},
{ id: "sentry", title: "Use Sentry for Error tracking", description: "Our extension partner Sentry provides an application monitoring platform that helps you identify and fix software problems before they impact your users. Fly.io organizations get a year's worth of [Sentry Team Plan](https://fly.io/docs/monitoring/sentry/#sentry-plan-details) credits. Read how to configure [Application Monitoring by Sentry](/docs/monitoring/sentry/)."},
{ id: "export-logs", title: "Export your logs", description: "Set up the Fly Log Shipper to aggregate your app’s logs to a service of your choice. Read more about [Exporting logs](/docs/monitoring/exporting-logs/)."}
],
c: params[:c] || "",
o: params[:o] || "",
h: params[:h] || ""
) %>
## CI/CD
<%= render ChecklistComponent.new(
items: [
{ id: "review-apps", title: "Generate review apps with GitHub Actions", description: "Automatically generate ephemeral review apps on Fly.io for each pull request (PR) using GitHub Actions. Learn more about [Git Branch Preview Environments on GitHub](/docs/blueprints/review-apps-guide/)."},
{ id: "deploy-with-github-actions", title: "Deploy with GitHub Actions", description: "Set up your app for continuous deployment to Fly.io from the app’s GitHub repository. Find out how to use [Continuous Deployment with Fly.io and GitHub Actions](/docs/app-guides/continuous-deployment-with-github-actions/)."}
],
c: params[:c] || "",
o: params[:o] || "",
h: params[:h] || ""
) %>
## Get support
<%= render ChecklistComponent.new(
items: [
{ id: "community", title: "Get answers in our community forum", description: "Check out our [community forum](https://community.fly.io/) to talk about your project and get help."},
{ id: "email-support", title: "Consider a purchasing a support plan", description: "Standard, Premium, or Enterprise support packages are available to purchase. Learn more about [Support plans](https://fly.io/support)."}
],
c: params[:c] || "",
o: params[:o] || "",
h: params[:h] || ""
) %>
Going to production checklist
Use this checklist to help you set up a production environment on Fly.io.
Overview
Moving an app from staging to production can expose unexpected failure modes: security holes, performance and scaling issues, or data loss. This checklist is meant to catch common pitfalls for apps on Fly.io, but it’s not a guarantee of production readiness. Not every item here will apply to your app, and you may have additional requirements that aren’t listed. Use this as a foundation and adapt it to your needs. Think of this list as a scaffold, not a silver bullet.
Important: The checklist is not exhaustive and does not guarantee production-readiness for your app. Apps can have unique requirements for production depending on the framework and type of app. Some items won’t be applicable and there may be other considerations not listed here; you’ll need to decide which checklist items work for your app.
Security
Set up single sign-on for organizations
Enable SSO on your organization to take advantage of Google or GitHub authentication security. Learn more about Single sign-on for organizations.
Use access tokens to allow only the minimum access level required by team members to your organization, apps, and Machines. Understand access tokens.
Protect sensitive information
Set secrets to store sensitive data and make them available as environment variables to your app. Read about Secrets and Fly Apps.
Make sure private services are not exposed
Check that your private apps with services don’t have public IP addresses. Run fly ips list and use fly ips release to release unnecessary public IPs. More detail is available in this flyctl reference: fly ips commands. Assign private apps a Flycast address instead.
Use Arcjet application security for JavaScript apps
Secure your app with rate limiting, bot protection, email validation, and defense against common attacks through our extension partner Arcjet. Read more about Application Security by Arcjet.
Databases
Use Managed Postgres
We recommend using Fly.io’s Managed Postgres, our fully-managed database service that handles all aspects of running production PostgreSQL.
Practice your disaster recovery plan
Practice restoring your managed Postgres database from a backup before you actually need to. You can do this anytime from the Managed Postgres dashboard.
App performance
Get Machine sizing right
Most conventional production web apps require performance CPUs. Also make sure you have enough RAM for your app and/or enable swapping to disk to deal with brief spikes in memory use. Find out more details in our Machine sizing guide.
Make your app resilient to single-host failures with multiple Machines that stay stopped until you need them. Learn more in our guide: Resilient apps use multiple Machines.
Scale your app into more regions
Scale your app in multiple regions closest to your app’s users. Find out how to Scale an app’s regions.
Use autostop/autostart to reduce costs
Autostop/autostart lets you stop or suspend Machines when there’s low traffic, saving on resource usage and costs. You get autostop/autostart by default with a new app, but you can configure it to optimize for your use case. Find out more: Autostop/autostart Machines.
Set up autoscaling by metric to reduce costs
For apps that aren’t running web services, use the autoscaler app to scale your app’s Machines based on any metric, saving on resource usage and costs. Learn how to Autoscale based on metrics.
Completely eliminate the chance of blacklisted spammers causing problems for your app. There is a small added cost for dedicated IPv4 addresses. Read more about Dedicated IPv4.
Set up Flycast for private apps
If you haven’t already done so, give your private apps a Flycast address to communicate with them entirely on your private network. Find out about Flycast - Private Fly Proxy services.
Monitoring
Monitor your app with fully-managed metrics
Use managed Prometheus and managed Grafana dashboards to monitor your app. Read about Metrics on Fly.io.
Use Sentry for Error tracking
Our extension partner Sentry provides an application monitoring platform that helps you identify and fix software problems before they impact your users. Fly.io organizations get a year’s worth of Sentry Team Plan credits. Read how to configure Application Monitoring by Sentry.
Export your logs
Set up the Fly Log Shipper to aggregate your app’s logs to a service of your choice. Read more about Exporting logs.