Getting Started
Services
Coherence supports any application that can be containerized and which serves HTTP traffic. Here are some common examples. Be sure to review the documentation on database seeding and loading data from database snopshots, which apply to all Coherence applications.
Redwood.js
You can setup Redwood to deploy on Coherence with AWS or GCP with yarn rw setup deploy coherence
. It should "just work" when you go through the onboarding flow at app.withcoherence.com
.
A few notes:
prerender
functionality for theweb
side is disabled by default. Get in touch with us to discuss how to enable it.- The default
docker
images will be built withnixpacks
. The first build will take 15-20 minutes for your app to build and deploy, it should go below 10 mins for future builds (aside from when dependencies or OS base images change). To speed up deployments to an environment even more, you can createweb
andapi
specificDockerfile
's and get smaller and more controlled images. You can create theDockerfile
for each side, e.g.Dockerfile.web
and then can configure Coherence to use it as theprod.dockerfile
for each service. See here for some rough examples.
The default redwood
CLI command will setup one coherence.yml
file where the web
side serves at /
and the api
side serves from the same domain at /api
. The yml
looks like:
api:
type: backend
url_path: "/api"
prod:
command: ["yarn", "rw", "build", "api", "&&", "yarn", "rw", "serve", "api", "--apiRootPath=/api"]
dev:
command: ["yarn", "rw", "build", "api", "&&", "yarn", "rw", "dev", "api", "--apiRootPath=/api"]
local_packages: ["node_modules"]
system:
cpu: 2
memory: 2G
health_check: "/api/health"
resources:
- name: YOURNAME-db
engine: postgres
version: 14
type: database
adapter: postgresql
# If you use data migrations, use the following instead:
# migration: ["yarn", "rw", "prisma", "migrate", "deploy", "&&", "yarn", "rw", "data-migrate", "up"]
migration: ["yarn", "rw", "prisma", "migrate", "deploy"]
web:
type: frontend
assets_path: "web/dist"
prod:
command: ["yarn", "rw", "serve", "web"]
dev:
command: ["yarn", "rw", "dev", "web", "--fwd=\\"--allowed-hosts all\\""]
# Heads up: Redwood's prerender doesn't work with Coherence yet.
# For current status and updates, see https://github.com/redwoodjs/redwood/issues/8333.
build: ["yarn", "rw", "build", "web", "--no-prerender"]
local_packages: ["node_modules"]
system:
cpu: 2
memory: 2G
An alternate approach is to setup 2 different coherence.yml
files with 2 different apps. If you're migrating from a service where you had a subdomain for each service (e.g. api.yourcompany.com
and app.yourcompany.com
) you might want to use this approach. Read more about routing in a monorepo here. If you want to set this up, please get in touch so we can configure the yml
filenames for your app. The yml
in this approach will look like this:
coherence.api.yml (or whatever you want):
api:
type: backend
prod:
command: ["yarn", "rw", "build", "api", "&&", "yarn", "rw", "serve", "api"]
dev:
command: ["yarn", "rw", "build", "api", "&&", "yarn", "rw", "dev", "api"]
local_packages: ["node_modules"]
system:
cpu: 2
memory: 2G
health_check: "/health"
resources:
- name: YOURNAME-db
engine: postgres
version: 14
type: database
adapter: postgresql
# If you use data migrations, use the following instead:
# migration: ["yarn", "rw", "prisma", "migrate", "deploy", "&&", "yarn", "rw", "data-migrate", "up"]
migration: ["yarn", "rw", "prisma", "migrate", "deploy"]
coherence.app.yml (or whatever you want):
web:
type: frontend
assets_path: "web/dist"
prod:
command: ["yarn", "rw", "serve", "web"]
dev:
command: ["yarn", "rw", "dev", "web", "--fwd=\\"--allowed-hosts all\\""]
# Heads up: Redwood's prerender doesn't work with Coherence yet.
# For current status and updates, see https://github.com/redwoodjs/redwood/issues/8333.
build: ["yarn", "rw", "build", "web", "--no-prerender"]
local_packages: ["node_modules"]
system:
cpu: 2
memory: 2G
By using build glob configuration you can minimize the duplicated builds across both apps each time you push when configuring more than one app in a repo.
React Exmaple
See a full example repo here.
frontend:
type: frontend
assets_path: dist
local_packages: ["node_modules"]
build: ["yarn", "build"]
dev: ["yarn", "dev"]
Django Example
See a full example repo (this repo includes a react frontend and a django backend) here.
Here's an example video of setting up a Django app
A few other things you'd want to do:
- Install dj-database-url package to easily get the right database configuration. You can add this to your
requirements.txt
file.- If you're using GCP, you also want to set the
HOST
property of your database configurations to be/cloudsql/INSTANCE_NAME
using the_INSTANCE
value on theVariables
tab of your Coherence environments.
- If you're using GCP, you also want to set the
- Make sure to use
COHERENCE_DEV
environment variable to set theDEBUG
value in your settings. - Add the
COHERENCE_ENVIRONMENT_DOMAIN
andCOHERENCE_CUSTOM_DOMAIN
to theALLOWED_HOSTS
settings to prevent CORS issues. - You can configure the
prod
command to use another python WSGI server like gunicorn as well by changing the command in theyaml
configuration below.
See the Environment Variables docs for more info on the variables mentioned above.
The /opt/venv/bin/activate
command is needed due to how nixpacks
handles python installs. You can remove that command (including the &&
) if you use your own Dockerfile and python packages are available on the PATH
by default.
server:
type: backend
migration: [".", "/opt/venv/bin/activate", "&&", "python", "manage.py", "migrate"]
dev: [".", "/opt/venv/bin/activate", "&&", "python", "manage.py", "runserver", "0.0.0.0:$PORT"]
prod: [".", "/opt/venv/bin/activate", "&&", "python", "manage.py", "runserver", "0.0.0.0:$PORT"]
resources:
- name: db1
engine: postgres
version: 14
type: database
adapter: postgresql
Rails Example
If you use the Nixpacks
builder (the Coherence default if you don't define a Dockerfile
) than the asset precomile step will be handled for you. If you write a Dockerfile
be sure to include it. The /root/.profile
command is needed due to how nixpacks
handles ruby gem installs. You can remove that command (including the &&
- meaning just use bundle
directly) if you use your own Dockerfile and ruby gems are available on the PATH
by default.
See an example of setting up a Ruby on Rails app
rails:
type: backend
migration: [".", "/root/.profile", "&&", "bundle", "exec", "rails", "server:migrate"]
dev: [".", "/root/.profile", "&&", "bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
prod: [".", "/root/.profile", "&&", "bundle", "exec", "rails", "server", "-e", "production", "-b", "0.0.0.0"]
system:
memory: 2G
cpu: 2
resources:
- name: db1
engine: postgres
version: 14
type: database
You will also want to modify the database.yml
(and any other initializers you use, like S3/GCS for storage or redis for cache) to read their config from the appropriate Coherence-supplied environment variables. See the Environment Variables docs for more info on the variables. Here's a simply database.yml
example:
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
url: <%= ENV["DATABASE_URL"] %>
test:
<<: *default
url: <%= ENV["DATABASE_URL"] %>
production:
<<: *default
url: <%= ENV["DATABASE_URL"] %>
You'll also want to edit the application.rb
initializer and edit the allowed hosts of your app. You might already have some entries for this in environment settings (e.g. development
) so be careful not to break those. These are a bit loose but are intended as an example (but they'll work):
config.hosts = [
IPAddr.new("10.0.0.0/8")
]
config.hosts << /.*\.coherencedev\.com\z/
config.hosts << /.*\.coherencesites\.com\z/
Last, you'll also need to set any relevant environment variables required by your app, for example the SECRET_KEY_BASE
variable. You can use the Coherence Variables
UI to set these.
flask example
flask is a popular python web framework. This is a simple example, assuming your app does not need a database and that your app.py
file runs the flask server on the PORT
environment variable provided by Coherence when it is run via python
. You can configure the dev
or prod
commands to use flask run
or another python WSGI server like gunicorn as well by changing the commands in the yaml
configuration below.
You can also add a database and cache easily, see the other examples on this page including the redwood
and Rails
examples above for syntax, nothing special needs to be done for flask
itself, aside from listening to the appropriate variables to configure your database connections, e.g. DATABASE_URL
.
backend:
type: "backend"
dev: ["python", "app.py"]
prod: ["python", "app.py"]
FastAPI example
FastAPI is a popular python web framework. In this example, you've got a postgres database and are using uvicorn
to serve the application. You'd change the app:app
reference to follow the path to your actual app instance as per the FastAPI docs.
The /opt/venv/bin/activate
command is needed due to how nixpacks
handles python installs. You can remove that command (including the &&
) if you use your own Dockerfile
and python packages are available on the PATH
by default.
backend:
type: backend
prod: [".", "/opt/venv/bin/activate", "&&", "uvicorn", "app:app", "--port=$PORT", "--host=0.0.0.0", "--reload"]
dev: [".", "/opt/venv/bin/activate", "&&", "uvicorn", "app:app", "--port=$PORT", "--host=0.0.0.0", "--reload"]
resources:
- name: db1
engine: postgres
version: 15
type: database
Next.js Example
There are 2 common configurations used for Next.js. One is static export where your site ends up as single page app served from a CDN. The other (more common) configuration is where you run a server process and this configuration supports functionality such as server-side rendering, API routes, and database-backed services. See more in the Next docs.
See an example of setting up a server
type
For running a server process, use the backend
service type on Coherence. See a full example repo here.
backend:
type: backend
local_packages: ["node_modules"]
dev: ["npm", "run", "dev"]
prod: ["npm", "run", "start"]
For deploying a single page app, use a frontend
service type.
frontend:
type: frontend
local_packages: ["node_modules"]
dev: ["npm", "run", "dev"]
build: ["npm", "run", "export"]
streamlit example
streamlit is a popular python framework for full-stack, data-driven apps. You'll also want to check the filename in the command below and replace streamlit_app.py
with your own app.
For database connection secrets, we recommend to use Coherence Variables and use the values in generating a Connection on streamlit (for most databases this means using the kwargs
in the streamlit experimental_connection
).
You can see a YouTube walk-though of setting up a streamlit app from scrach
streamlit:
type: "backend"
dev: ["streamlit", "run", "streamlit_app.py", "--server.port=$PORT", "--server.address=0.0.0.0", "--server.runOnSave=false"]
prod: ["streamlit", "run", "streamlit_app.py", "--server.port=$PORT", "--server.address=0.0.0.0"]
You might also want to use a Dockerfile
like this (otherwise we will use nixpacks
and you need to do the venv
commands similar to the Django example above):
FROM python:3.9-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \
build-essential \
curl \
software-properties-common \
git \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip3 install -r requirements.txt
COPY . .
Refine
Refine is a meta-framework for react admin apps. For the most part, it should be just like a standard react app as above. You can see a live walk-thru video setting up a refine example app below!
dashboard:
type: frontend
assets_path: dist
local_packages: ["node_modules"]
build: ["yarn", "build"]
dev: ["yarn", "start"]