Skip to main content

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

  1. Upload — the contents of your current directory are uploaded (minus anything in .cfignore)
  2. Detect — buildpacks inspect the source and decide what kind of application it is
  3. Build — dependencies are installed and a runnable image is produced
  4. 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.