Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 199 additions & 0 deletions docs/howtos/use-develop/app_watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
---
sidebar_label: Inner-loop development with app watch
sidebar_position: 5
title: Inner-loop development with app watch
description: Use epinio app watch to sync local changes into a running application without a full push.
keywords: [epinio, kubernetes, inner loop, live reload, app watch, hot reload]
doc-type: [how-to]
doc-topic: [epinio, how-to, use-develop, app-watch]
doc-persona: [epinio-developer]
---

`epinio app watch` shortens the edit-compile-test loop by syncing local changes
directly into a running pod, skipping the full buildpack pipeline on every save.

## How it works

`app watch` has two phases:

**Startup (first run)**

On the first run there is no local state file, so `app watch` performs a full
buildpack push to prime the build cache. It then patches the running deployment
to inject a supervisor wrapper as PID 1. The supervisor starts your app and
watches for an updated binary or source files delivered by the sync phase.

**Sync (subsequent runs)**

After startup, `app watch` polls the source directory every 500 ms. When it
detects a changed file it enters sync mode:

- **Binary mode** (compiled languages): runs your `build_cmd`, tars the output
binary, and uploads it to the running pod via the Epinio API. The pod-side
supervisor replaces the running binary and restarts the app in place.
- **Files mode** (interpreted languages): tars only the changed files and
uploads them into the pod's source directory. If your runtime watches for
file changes (Node.js, Python, etc.) it will pick them up automatically.

The mode is chosen by the presence of `build_cmd` and `binary` in
`.epinio-sync.yaml`. If neither is set, files mode is used.

## Prerequisites

- The application namespace is targeted (`epinio target <namespace>`) or you
pass `--namespace`.
- The application must be known to Epinio. `app watch` creates it on the first
push if it does not exist yet.
- Your workstation runs Linux, macOS, or Windows with WSL.

## Quick start

```console
cd my-app/
epinio app watch my-app
```

On first run this is equivalent to `epinio app push`. Once the startup push
completes, save any source file and the terminal will show sync progress:

```
Synced in 312ms (via API)
```

## Example configurations

### Go

Go is a compiled language so binary mode is used. Add `.epinio-sync.yaml` to
your project root:

```yaml
# .epinio-sync.yaml
build_cmd: "CGO_ENABLED=0 go build -o ./bin/my-app ."
binary: "./bin/my-app"
```

On every save, `app watch` runs `build_cmd`, uploads the new binary into the
pod, and the supervisor restarts the app automatically. No extra tooling
required.

Delete `.epinio-patch-state` and re-run `app watch` after `go.mod` changes
to trigger a fresh buildpack run that re-resolves dependencies.

### Node.js

Node.js is interpreted so no `build_cmd` or `binary` is needed. Files mode
is the default. On every save, changed files are synced into the pod and the
running process is restarted cleanly by the supervisor.

No `.epinio-sync.yaml` is required for a standard Paketo Node.js app.

If your source layout differs from the Paketo default, add a `files_dest`
override:

```yaml
# .epinio-sync.yaml
files_dest: "/workspace/source/app"
```

### Python

Python works the same way as Node.js -- files mode with no `build_cmd`. On
every save, changed `.py` and template files are synced into the pod and the
interpreter restarts fresh.

No `.epinio-sync.yaml` is required for a standard Paketo Python app.

```yaml
# .epinio-sync.yaml (only needed for non-standard layouts)
files_dest: "/workspace/source/app"
```

## All configuration options

Place `.epinio-sync.yaml` in the root of your source directory to configure
binary mode or override defaults. All fields are optional.

| Field | Default | Description |
|---|---|---|
| `build_cmd` | — | Shell command to build the binary. When set alongside `binary`, enables binary mode. |
| `binary` | — | Path to the built binary relative to the source root. |
| `binary_dest` | `/epinio-sync/app` | Destination path inside the pod for the synced binary. Only change this if the supervisor is configured to match. |
| `files_dest` | `/workspace/source/app` | Destination directory inside the pod for files mode syncs. |
| `process_cmd` | auto-discovered | Command the supervisor runs to start the app on first boot. By default it uses `/cnb/process/web` when the buildpack defines it, otherwise the image's first CNB process. Override for non-CNB images. |

### Non-CNB builders

Cloud Native Buildpacks images are handled automatically. If your builder
produces an image without `/cnb/process` entries, set `process_cmd` to the
command that starts your app, and `binary_dest` or `files_dest` to match
wherever the builder places the workload:

```yaml
process_cmd: "/app/bin/start"
binary_dest: "/app/bin/my-app"
```

## Ignoring files

`app watch` respects the same ignore rules as `epinio push`:

| File | Purpose |
|---|---|
| `.gitignore` | Standard git ignore patterns. Matched files are excluded from sync. |
| `.epinioignore` | Epinio-specific ignores. Use this for files you want in git but not in the push (e.g. test fixtures, local config). |

Patterns from both files are combined. Either file may be absent.

The watch state file (`.epinio-patch-state`) and config file
(`.epinio-sync.yaml`) are always excluded automatically.

### Performance on large codebases

To detect changes, `app watch` hashes every non-ignored file in the source
directory on each poll cycle (every 500 ms). On a large codebase this adds
noticeable CPU and disk load, and slows down change detection.

Use the ignore files to keep the watched set small. Dependency directories
and build output are the usual offenders:

```gitignore
# .epinioignore (or .gitignore)
node_modules/
vendor/
.venv/
dist/
bin/
*.log
```

Everything excluded here is also excluded from the sync payload, so a tight
ignore list makes both change detection and uploads faster.

## State file

`app watch` writes `.epinio-patch-state` in the source directory after a
successful startup push. This file records the file hashes used to detect
changes on the next run.

If this file is present, `app watch` skips the startup push and goes straight
into sync mode. To force a fresh startup push (for example, after a dependency
change), delete the state file:

```console
rm .epinio-patch-state
epinio app watch my-app
```

## CLI flags

| Flag | Default | Description |
|---|---|---|
| `--namespace`, `-n` | targeted namespace | Namespace the application lives in |
| `--path` | current directory | Path to the application source directory |

## See also

- [epinio app push](../../references/commands/cli/epinio_push.md) — full push without watching
- [epinio app watch (reference)](../../references/commands/cli/app/epinio_app_watch.md) — CLI flag reference
- [Debugging an application](./debug.md) — attaching a debugger to a running app
1 change: 1 addition & 0 deletions docs/references/commands/cli/app/epinio_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,5 @@ epinio app [flags]
* [epinio app restart](./epinio_app_restart.md) - Restart the application
* [epinio app show](./epinio_app_show.md) - Describe the named application
* [epinio app update](./epinio_app_update.md) - Update the named application
* [epinio app watch](./epinio_app_watch.md) - Watch a local directory and sync changes to the running application

57 changes: 57 additions & 0 deletions docs/references/commands/cli/app/epinio_app_watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
sidebar_label: epinio app watch
title: ""
description: epinio app watch
keywords: [epinio, kubernetes, epinio app watch]
doc-type: [reference]
doc-topic: [epinio, reference, epinio-cli, epinio-app-watch]
doc-persona: [epinio-developer]
---
## epinio app watch

Watch a local directory and sync changes to the running application

```
epinio app watch NAME [flags]
```

### Description

Watches the source directory for changes and syncs them into the running pod.

On the first run (no local state file) a full buildpack push is performed and
the running deployment is patched with a supervisor wrapper. On subsequent runs
only changed files or the rebuilt binary are uploaded via the Epinio API,
without going through the buildpack pipeline.

Configure binary mode (compiled languages) or override sync paths by placing
an `.epinio-sync.yaml` file in the source directory.
See [Inner-loop development with app watch](../../../../howtos/use-develop/app_watch.md)
for a full guide.

### Options

```
-h, --help help for watch
-n, --namespace string Namespace the application lives in (overrides targeted namespace)
--path string Path to the application source directory (defaults to current directory)
```

### Options inherited from parent commands

```
-H, --header stringArray Add custom header to every request executed
-c, --kubeconfig string (KUBECONFIG) path to a kubeconfig, not required in-cluster
--no-colors Suppress colorized output
--settings-file string (EPINIO_SETTINGS) set path of settings file (default "~/.config/epinio/settings.yaml")
--skip-ssl-verification (SKIP_SSL_VERIFICATION) Skip the verification of TLS certificates
--timeout-multiplier int (EPINIO_TIMEOUT_MULTIPLIER) Multiply timeouts by this factor (default 1)
--trace-file string (TRACE_FILE) Print trace messages to the specified file
--trace-level int (TRACE_LEVEL) Only print trace messages at or above this level (0 to 255, default 0, print nothing)
--trace-output string (TRACE_OUTPUT) Sets trace output format [text,json] (default "text")
--verbosity int (VERBOSITY) Only print progress messages at or above this level (0 or 1, default 0)
```

### SEE ALSO

* [epinio app](./epinio_app.md) - Epinio application features