Getting started
Moving from Laravel Vapor
From vapor.yml to brewless.yml in one command, then your variables, the data in your database and your domain, with what each Vapor key becomes.
On this page
A Laravel application on Vapor has its environments described in vapor.yml. brewless init reads that file once, writes the brewless.yml that says the same wherever Brewless has a setting for it, and tells you what it could not carry over. Nothing at Vapor or AWS is read or changed: your application keeps running there until you move your domain.
You need what the quickstart asks for: a Scaleway account connected to your organisation at Brewless, and the command line client, signed in.
1. Write brewless.yml from vapor.yml
In the root of the project, next to vapor.yml:
brewless init --from-vapor
init asks which application at Brewless this is, or makes a new one, and writes brewless.yml. It then adds the environments of vapor.yml you pick, in the region you choose, and sets each one up the way it was at Vapor: a new database where it had one, a queue at Scaleway Queues unless it said queues: false, and a bucket where it had storage. An environment whose jobs wait in its database at Brewless can move them to a queue later with queue: sqs in brewless.yml. It says what that comes to and makes it after one yes. Without --from-vapor, init asks whether to start from the vapor.yml it finds.
Take this vapor.yml:
id: 12345
name: shop
environments:
production:
runtime: 'php-8.4:al2023'
memory: 1024
cli-memory: 512
warm: 10
queue-timeout: 540
database: shop-db
storage: shop-files
gateway-version: 2
domain:
- shop.example.eu
- www.shop.example.eu
build:
- 'composer install --no-dev'
- 'npm ci && npm run build && rm -rf node_modules'
deploy:
- 'php artisan migrate --force'
staging:
runtime: 'php-8.4:al2023'
memory: 512
queues: false
scheduler: false
database: shop-staging-db
build:
- 'composer install --no-dev'
- 'npm ci && npm run build && rm -rf node_modules'
deploy:
- 'php artisan migrate --force'
With both environments added in Paris, init writes:
# Which application this is at Brewless. No secrets belong in this file.
organisation: acme
application: shop
framework: laravel
php: '8.4'
release:
- 'migrate --force'
environments:
production:
kind: production
region: fr-par
web:
memory: 1024
min: 1
release:
memory: 512
worker:
timeout: 540
database: shop-db
queue: sqs
storage: shop-files
domains:
- shop.example.eu
- www.shop.example.eu
staging:
kind: staging
region: fr-par
web:
memory: 512
scheduler: false
database: shop-staging-db
queue: false
and prints, once each, what it did not carry over as it was:
Not carried over from vapor.yml as it was:
- `warm` (production): Vapor kept 10 Lambda containers warm, each taking one request at a time; a replica at Brewless takes up to 50, so `web.min` is 1. …
- `gateway-version` (production): There is no API Gateway at Brewless: visitors reach the web container through bunny.net, or its own address without it.
- `build`: Left out, as Brewless does it itself: composer install --no-dev, npm ci, npm run build, rm -rf node_modules.
These lines are printed in the terminal only; the file stays clean. The table below lists every key. Commit brewless.yml: it holds no secrets.
2. Check it with brewless plan
brewless plan
shows per environment what the file asks for next to what stands now, and changes nothing. A key Brewless refuses comes with its line in the file. Every key and its bounds are on brewless.yml, which also says what a deploy does with each of them today.
brewless.yml names each database and bucket as vapor.yml does. A database or bucket that init made has a name of its own, after the application and the environment, so the plan shows the two next to each other: write the name that stands in brewless.yml.
3. Your variables and secrets
vapor.yml holds no variables, and Brewless never reads them from Vapor. The environments Brewless set up have variables of their own already: the database, the queue, the bucket and a new APP_KEY. Fetch those into a file of their own, so they do not mix with a file of Vapor's:
brewless env:pull production --file=.env.brewless-production
Add to it what your application needs besides, from your variables and secrets at Vapor: mail, payment and other services, for instance. Keep the DB_*, AWS_*, SQS_*, QUEUE_CONNECTION and FILESYSTEM_DISK lines Brewless wrote: they point at the new database, queue and bucket. Take your APP_KEY from Vapor instead of the new one when your application has encrypted data or sessions: Laravel reads those only with the key they were written with. Then push it and remove the file:
brewless env:push production --file=.env.brewless-production
rm .env.brewless-production
Plain values that are no secret, such as APP_LOCALE, can go under variables in brewless.yml instead. See Environment variables.
4. The data in your database
The database Brewless set up is empty, and the data is not moved for you. A Serverless SQL Database speaks PostgreSQL. From a machine that can reach the database at Vapor, dump it and load it into the new one, with the address and credentials from brewless env:pull:
pg_dump --no-owner --no-privileges "postgresql://user:password@old-host:5432/shop" > shop.sql
psql "postgresql://$DB_USERNAME:$DB_PASSWORD@$DB_HOST:$DB_PORT/$DB_DATABASE?sslmode=require" < shop.sql
Do this before your first deploy, so the release commands find your tables. A MySQL database at Vapor needs a MySQL database to move to, such as a Managed Database you name when you set the environment up; Brewless does not convert data between the two. Leave your application at Vapor in maintenance mode while you move, or move again just before you switch the domain, so no writes are lost.
The files in your S3 bucket are not moved either: copy them into the new bucket with a tool that speaks S3 to both.
5. Deploy
brewless deploy production
builds the current commit, runs the release commands and puts the release live on the address of the environment, such as acme-shop-production.b-cdn.net, and on its test address. Try it there while your domain still points at Vapor. The deploy names the domains of brewless.yml that the environment does not answer on yet and asks whether to add them: answer no until you move your domain, because adding one points its DNS at Brewless when the zone is in your accounts. See Deployments.
6. Your domain
When the release on Brewless does what it should, move your domain over: init printed a brewless domain:add line for every domain of the environments it added. Moving your domain to Brewless walks through the DNS zone, the records in the way and APP_URL. Once visitors arrive at Brewless, what you had at Vapor can go: Brewless never removes anything there.
vapor.yml next to brewless.yml
Same means the value is carried over as it is. Works differently means it is carried over in another form, or partly. Not available means Brewless has no setting for it; init says so when your file has the key.
| vapor.yml | brewless.yml | Status | What happens |
|---|---|---|---|
id, name |
organisation, application |
Works differently | init asks which application at Brewless the project is, or makes one. |
runtime: php-8.4:al2023 |
php: "8.4" |
Same | One version for all environments, that of production or else the first; 8.3 and later. |
runtime: docker, -arm |
– | Not available | Brewless builds the image itself on its public base image and chooses the processor. |
memory |
web.memory |
Same | Megabytes, from 128 to 12288; the processor follows the memory. |
timeout |
web.timeout |
Same | Seconds, from 10 to 3600; a value outside is brought within. |
warm |
web.min |
Works differently | Replicas that keep running. One replica takes up to 50 requests at once and a Lambda container one, so warm: 10 becomes 1. A running replica is paid for all the time. |
concurrency |
web.max |
Works differently | The most replicas, worked out the same way: concurrency: 120 becomes 3. |
tmp-storage |
web.tmp-storage |
Same | From 1000 megabytes up to four times the memory. Less than 1000 is left out: every container gets 1000. |
cli-memory, cli-timeout |
release.memory, release.timeout |
Works differently | The container the release commands run in. The commands themselves get 90 seconds per release. |
queue-memory, queue-timeout |
worker.memory, worker.timeout |
Same | The container that works the queue and the schedule. |
queues |
worker.queues, queue |
Works differently | The names, the first being the default; a number of jobs per queue is not carried. Every environment gets queue: sqs, a queue at Scaleway Queues, or queue: false for queues: false. As at Vapor, a job on the queue starts the worker by itself; see how the worker is called. |
queue-concurrency |
– | Not available | Every minute a trigger calls the worker for the schedule and then the queue. |
scheduler |
scheduler |
Same | sub-minute becomes true: the schedule runs every minute. |
build |
build |
Works differently | One list for all environments, that of production. Steps Brewless runs itself are left out: composer install, the frontend build when there is a package-lock.json, removing node_modules, and caching configuration, routes and views. |
deploy |
release |
Works differently | Artisan commands, without php artisan in front; one list for all environments. Other commands are left out. Without it, your application's own release commands run. |
domain |
domains |
Same | brewless deploy names those the environment does not answer on yet and adds them after a yes; or add each one with brewless domain:add. See Domains. |
database |
database |
Same | The database by name; its data is not moved. At Vapor a database is shared by name, within one team and region. At Brewless an environment can be linked to a database in its region, also one of another application, with a login of its own; see Databases. |
storage |
storage |
Same | The bucket by name; its files are not moved. |
cache |
– | Not available | Brewless sets up no cache. Use a cache store of Laravel, such as the database, or a Redis of your own with its variables in Secret Manager. |
network, balancer |
– | Not available | Visitors reach the web container through bunny.net, or its own address without it. |
firewall |
– | Not available | Brewless has no firewall setting. |
gateway-version |
– | Not available | There is no API Gateway in between. |
octane |
– | Not available | Brewless serves the application with FrankenPHP in its classic mode. |
database-user, database-proxy |
– | Not available | The database user is in your variables (DB_USERNAME). |
layers, separate-vendor |
– | Not available | The image is built on Brewless's public base image and holds the vendor directory. |
ignore |
– | Works differently | A deploy packs what is committed with git archive: leave paths out with export-ignore in .gitattributes. |
An environment name Brewless does not take, such as one with capitals or underscores, is left out with a line that says so. Each environment gets the kind of its name (production, staging) or development, and the region it was added in.