Projects & Apps

Migrate a Laravel App and Its MySQL Database to FlyNode

Deploy an existing Laravel project from Git, move its MySQL data to a managed database, and set the variables Laravel needs behind FlyNode's proxy.

5 min read Updated Oct 12, 2026

Browse documentation

Need a hand?

Can't find your answer? Our team replies fast.

Contact support

This guide moves an existing Laravel app that uses MySQL to a FlyNode Cloud Workspace. The app runs as a Custom app built from your Git repository. The database stays on a MySQL host you choose and the app reaches it through the usual DB_* variables.

How the pieces fit

  • Laravel app: one Custom app. FlyNode builds your repository with Nixpacks, which recognises a Laravel project, runs composer install and your front-end build, and serves the app with nginx and PHP-FPM on a generated address with automatic SSL.
  • MySQL: a managed MySQL service or a server you already run. Apps on FlyNode cannot reach each other's databases, so the app connects to the database by its normal address. A Custom app does not start a MySQL of its own.
  • Not included: queue workers and the scheduler are separate processes. This app serves web requests only, so use a queue driver and scheduler that do not need a long-running process on this container (or run them elsewhere).

Before you start

  • Your code is in a repository on GitHub, GitLab or Bitbucket, and it does not contain your real .env file.
  • You know your app key (php artisan key:generate --show prints one), your database login, and every other setting your .env holds.
  • For a private repository, read Deploy a Private Repository first, and see the note in step 3.

Step 1: Get the code ready

  • Trust the proxy. FlyNode serves your app over HTTPS in front of the container. Without trusting the proxy, Laravel builds http:// links for your CSS and JavaScript and the browser blocks them, so the page loads with no styling. In Laravel 11 and 12, add this to bootstrap/app.php:
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->trustProxies(at: '*');
    })
    If you cannot change the code yet, set the APP_URL and ASSET_URL variables to your https:// address (step 4). We tested that this makes the CSS and JavaScript load.
  • Keep files out of the container. A deploy builds a new container, so files written to storage at run time are not kept. Use S3 or another object store for uploads.
  • Sessions and cache. If your app uses the database for sessions or cache, those tables must exist in the new database before the first visit (step 2).

Step 2: Move the database

  1. Create a MySQL database at your provider. Note its host, port, name, user and password. Most managed services require SSL, so keep the connection option your provider documents.
  2. If the provider limits which addresses may connect, allow your FlyNode server. If a connection is refused later, check this first.
  3. On your own computer, take a dump of the old database: mysqldump --single-transaction --routines --triggers -u USER -p OLD_DB > dump.sql.
  4. Load it into the new one: mysql -h NEW_HOST -u NEW_USER -p NEW_DB < dump.sql.
  5. Check a few table row counts in both databases before you switch.

Step 3: Deploy the app

  1. Go to Deploy and choose Custom app.
  2. Enter an app name, choose Public repository or Private repository, paste the repository address and check the branch.
  3. Leave Advanced build options alone. FlyNode detects Laravel on its own.
  4. Press Continue, keep the generated domain, press Continue again and then Deploy App.
The Custom app form with the repository, branch and advanced build options

Laravel on a private repository. For a public GitHub repository FlyNode sets one extra variable for you, NIXPACKS_START_CMD, which you will see in the Variables list. It works around a known problem where the web server never starts for Laravel projects (the log shows nginx: [emerg] duplicate location "/"). FlyNode cannot look inside a private repository to see that it is Laravel, so for a private one add the variable yourself: in Settings, Variables add NIXPACKS_START_CMD with this value, then press Save and redeploy:

env -u NIXPACKS_PHP_FALLBACK_PATH node /assets/scripts/prestart.mjs /assets/nginx.template.conf /nginx.conf && (php-fpm -y /assets/php-fpm.conf & nginx -c /nginx.conf)

Step 4: Add your variables

Open the app, go to Settings and then Variables. Use Paste a .env to add everything at once, then press Save and redeploy. These are the ones most Laravel apps need:

  • APP_KEY, APP_ENV=production, APP_DEBUG=false
  • APP_URL and ASSET_URL, both set to your https:// address
  • DB_CONNECTION=mysql, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD
  • SESSION_DRIVER and CACHE_STORE (for example file, or database once the tables exist)
The Variables list of a Laravel app with its settings and the Save and redeploy button

Values stay hidden until you press the eye icon. A variable is read when the app starts, so nothing takes effect until the app is deployed again. See Build Logs, Environment Variables and Rollback.

Step 5: Run your migrations

If the database you moved already holds your tables, you can skip this. To run migrations, open the Terminal tab. It opens in the root folder, and your project is in /app, so run cd /app first and then php artisan migrate --force. A command is stopped after 15 seconds, so this is meant for small jobs.

The Terminal tab showing the error from running php artisan in the wrong folder

Step 6: Check that it works

  1. Settings, then Deploys shows the build as Succeeded. If it failed, press View log.
  2. Open the app's address. A fresh Laravel project shows its welcome page.
The Laravel welcome page running on a FlyNode address

Then sign in and open a page that reads from MySQL. Add your own domain from the Custom Domain tab (see Custom Domains for Your Apps) and update APP_URL and ASSET_URL to it.

If something goes wrong

  • The page shows a plain 500 error. Most often the APP_KEY is missing, or the database is unreachable. Open the Logs tab, and set APP_DEBUG=true for a moment (then redeploy) if you need the full message. Turn it off again afterwards.
  • The page loads with no styling. Your CSS and JavaScript are requested over http://. Trust the proxy (step 1) or set ASSET_URL to your https:// address.
  • The address shows "no available server". The web server did not start. Read the Logs tab. If you see duplicate location "/", add the NIXPACKS_START_CMD variable from the note in step 3.
  • The database refuses the connection. Check the host, port and password, SSL if your provider requires it, and whether the provider restricts which addresses may connect.
  • Front-end build errors. Open Deploys and press View log. Make sure package.json has a build script that works on your own computer.

Next steps

Still stuck?

Open a support ticket from your dashboard and include the container name.

Contact support