Deploy from source
The core workflow is one command:
cf push orders-api
This page explains what that actually does, and how to influence it.
What happens on a push
- Upload — the contents of your current directory are uploaded (minus anything in
.cfignore) - Detect — buildpacks inspect the source and decide what kind of application it is
- Build — dependencies are installed and a runnable image is produced
- Start — the image is run with your configured instance count and memory
Detection is the interesting step. Buildpacks look for the signals your ecosystem
already uses — package.json for Node, requirements.txt or pyproject.toml for
Python, go.mod for Go, pom.xml or Gradle files for Java, Gemfile for Ruby. If your
project builds locally with standard tooling, detection usually just works.
Supported languages
The platform detects and builds these without any configuration from you:
- Node.js
- Python
- Go
- Java
- Ruby
- .NET
- Static sites
If your language is not listed, or your build needs something unusual, you can push a prebuilt image instead — see below.
Telling the platform how to start your app
Most buildpacks infer a start command. When they get it wrong, be explicit:
cf push orders-api -c "node dist/server.js"
Or commit a Procfile alongside your source:
web: node dist/server.js
Listening on the right port
Your app must listen on the port given in the PORT environment variable, not a
hardcoded one. This is the single most common reason a push builds successfully and
then fails to start.
const port = process.env.PORT || 3000;
app.listen(port);
Configuring the push
Command-line flags work for one-offs:
cf push orders-api -i 3 -m 1G
For anything you want repeated, commit a manifest.yml:
applications:
- name: orders-api
instances: 3
memory: 1G
command: node dist/server.js
env:
NODE_ENV: production
Then cf push reads it automatically.
Excluding files
Create a .cfignore in your project root — same syntax as .gitignore:
node_modules
.git
*.log
tmp/
Excluding node_modules is worth doing. The buildpack installs dependencies during the
build; uploading them makes the push slower for no benefit.
Pushing a prebuilt image
If you would rather build the image yourself:
cf push orders-api --docker-image registry.example.com/acme/orders-api:v2
The platform runs it as-is. Nothing else about the workflow changes — services bind the same way, logs and metrics work the same way.
When a push fails
Build failures print the buildpack output directly; the error is usually in the last twenty lines. Start-up failures are less obvious, because the build succeeded and the app died afterwards:
cf logs orders-api --recent
Look for the app crashing on boot. In order of likelihood: not listening on $PORT,
a missing environment variable, or a service that was bound without a subsequent
restart.
Deployment history
Every push is recorded. The console shows what was deployed and when, per app.