Setup project
First, initialize your project. Typenpx create-ship-app init in the terminal then choose desired build type and Digital Ocean Apps as a cloud service provider.

PostgreSQL
Ship runs on PostgreSQL via Drizzle ORM. Provision a DigitalOcean Managed PostgreSQL cluster for your app.Database creation
- In the DigitalOcean Control Panel, open the Databases tab and click
Create Database Cluster. - Select PostgreSQL as the database engine.
- Choose a region. We recommend the same region you set in your Pulumi config to keep latency low.
- Select a plan. A basic single-node plan is enough for staging/demo environments. For production, pick a plan with standby nodes and automated backups.
- Name the cluster and click
Create Database Cluster.
Connection
After the cluster is provisioned, open its Overview page and copy the connection string from the Connection Details section. This is yourDATABASE_URL value in the form postgresql://user:password@host:port/dbname?sslmode=require.
Save this value. You’ll add it to your Pulumi environment file in the next step.
The Pulumi program reads
DATABASE_URL from your environment file and passes it to the API, migrator, and scheduler resources as a secret env var. If you prefer to manage the database with Pulumi as well, you can declare a digitalocean.DatabaseCluster resource with engine: "pg" and wire its uri output into DATABASE_URL instead of pasting the value by hand.Redis Cloud
Navigate to Redis Cloud and create an account. Select cloud provider and region, then pressLet's start free to finish database creation.



redis://:<password@<public-endpoint>. Save this value. It will be needed later when creating the app in Digital Ocean.
Environment variables
TheAPP_ENV environment variable is typically set based on the environment in which the application is running.
Its value corresponds to the specific environment, such as “development”, “staging” or “production”.
This variable helps the application identify its current environment and load the corresponding configuration.
For the web application, by setting the environment variable APP_ENV,
the application can determine the environment in which it is running and load the appropriate configuration file:
| APP_ENV | File |
|---|---|
| development | .env.development |
| staging | .env.staging |
| production | .env.production |
VITE_ and read through import.meta.env (for example VITE_API_URL, VITE_WS_URL, VITE_WEB_URL). They are baked in at build time, so commit up-to-date values before you deploy.
In contrast, the API utilizes a single .env file that houses its environment-specific configuration.
This file typically contains variables like API keys, secrets, or other sensitive information.
To ensure security, it’s crucial to add the .env file to the .gitignore file,
preventing it from being tracked and committed to the repository.
So just specify the environment variables that will contain the values of your secrets.
For example, if you have a secret named API_KEY,
create an environment variable named API_KEY and set the value of the corresponding secret for it. The API needs at least DATABASE_URL (your PostgreSQL connection string) and REDIS_URI (your Redis connection string).
Digital Ocean via Pulumi
Pulumi is an open-source Infrastructure as Code (IaC) platform that allows developers to define and provision cloud infrastructure using familiar programming languages.Instead of using domain-specific languages or YAML templates, Pulumi leverages existing languages like TypeScript, Python, Go, and C#. The Ship Pulumi program defines the web app (TanStack Start), the API service, a pre-deploy migrator job that applies Drizzle migrations, and a scheduler worker. It injects
DATABASE_URL and REDIS_URI into the API, migrator, and scheduler as secret env vars.
Go to the /deploy directory at the root of your project and proceed to the next steps:
Pulumi CLI
Ensure you have Pulumi CLI installed.
After installing, verify everything is in working order by running the pulumi CLI:
After installing, verify everything is in working order by running the pulumi CLI:
Pulumi Login
Login in pulumi for managing your stacks:
DigitalOcean Tokens and Keys
Create your Personal Access Token and Access Keys for DigitalOcean
Configuring Tokens and Keys
Add DigitalOcean Personal Access Token and Access Keys to your configuration file: Insert the following variables at the end of the configuration file:To reflect the changes in the bash, either exit and launch the terminal again.Or use the command:
.zshrc or .bashrcFirst you’ll need to enter the .zshrc or .bashrc file in editing mode:GitHub apps
Grant DigitalOcean access to your GitHub repository using this link.
Stack initialization
Initialize your stack using the command:Substitute
Replace
{project-name} with the actual name of your project and make sure to update it in Pulumi.yaml file. Replace
{environment} with the desired environment: staging or production values are allowed.App environments
Duplicate the Populate the new file with the necessary environment variables.
.env.example file to create a new environment-specific file using the command:Ensure that you set the necessary variables in your web application.
Edit the .env files accordingly and remember to push these changes to your remote repository.

Cloudflare
Navigate to your Digital Ocean application and openSettings tab.
Navigate to Domains row to open domain settings and copy starter domain of application.

- Go to
DNStab and create a new record. - Click
Add record. Select typeCNAME, enter domain name (must be the same you entered in digital ocean settings) and paste alias intotargetfield. Make sureProxy statustoggle enabled. - Save changes

GitHub Actions
You can find two GitHub actions in the.github/workflows folder, responsible for triggering deployment when you push changes in your repository. If you chose frontend or backend on the initialization step, you’ll have one github workflow for the selected application type.
These actions require a Digital Ocean Personal Access Token and application ID.
Respectively these are DO_ACCESS_TOKEN and DO_API_STAGING_APP_ID/DO_WEB_STAGING_APP_ID/DO_API_PRODUCTION_APP_ID/DO_WEB_PRODUCTION_APP_ID.
Next, navigate to the Apps tab in the left sidebar and open your Digital Ocean application. You can find the id of your application id in the browser address bar.



Logging (optional)
Build-in
Digital Ocean has built-in logs in raw format. It will gather all data that your apps will produce. In order to view them, follow these steps:- Log in to your Digital Ocean account.
- Click on the Apps tab in the left-hand navigation menu.
- Click on the name of the app you want to view the logs for.
- Click on the Runtime Logs tab in the app dashboard.
- You will see a list of logs for different components of your app. Click on the component you want to view the logs for.
- You can filter the logs by time, severity, and component. Use the drop-down menus provided to select your filter criteria.
- You can also search for specific keywords in the logs by using the search bar at the top of the page.

Integrations
Currently, Digital Ocean Apps supports only 3 integrations: PaperTrail, Logtail and Datadog. You can find detailed instructions on how to set up these logs at this link.Example Integration Logtail
To configure Logtail follow these steps:- Create account on Logtail
- Open Sources on the left sidebar.
- Create new source by clicking “Connect source” button

- Select HTTP source and specify name for this connection

- Copy source token

- Open Digital Ocean Apps
- Select Settings tab for your application

- Select Log Forwarding and then press “Add Destination”

- Fill information with token that we retrieved from Logtail

- That’s it! In couple minutes your app will send the latest logs to Logtail

