This page covers the automated nightly build pipeline: how nightly dev tags are generated, how component hash history is validated and propagated, how packages are published to PyPI under nightly-specific names, and how Docker images are built and pushed. It also explains how a successful nightly build acts as a gate for all PR CI runs.
For information about standard (production) releases, see 8.3 For general CI pipeline structure, see 8.2
Langflow runs a nightly build every day at 00:00 UTC. The pipeline publishes three packages under nightly-specific names, builds Docker images, validates component hash history, and posts a Slack notification on completion or failure.
A key secondary effect is that a successful nightly publication acts as a prerequisite for all PR CI runs — if no nightly package was published today, CI on pull requests is blocked.
Involved workflow files:
| File | Role |
|---|---|
.github/workflows/nightly_build.yml | Top-level orchestrator |
.github/workflows/release_nightly.yml | Package build and publish logic |
.github/workflows/docker-nightly-build.yml | Docker nightly image builds |
.github/workflows/ci.yml | Contains the nightly status gate job |
.github/workflows/nightly_build.yml40-42
The workflow runs automatically via cron and can also be triggered manually via workflow_dispatch. The cron expression is 0 0 * * * (00:00 UTC daily).
Manual inputs allow selectively skipping frontend tests, backend tests, or Slack notification, and controlling whether images are pushed to registries. This is intended for testing the workflow itself without publishing.
The following diagram shows the full dependency graph of jobs in the nightly build pipeline.
Nightly Build Job Dependency Graph
Sources: .github/workflows/nightly_build.yml48-540
.github/workflows/nightly_build.yml58-182
The create-nightly-tag job is the first substantive step. It:
scripts/ci/pypi_nightly_tag.py main to compute a MAIN_TAG (e.g. v1.5.1.dev36).scripts/ci/pypi_nightly_tag.py base to compute a BASE_TAG.scripts/ci/lfx_nightly_tag.py to compute a LFX_TAG.scripts/ci/update_lfx_version.py to patch src/lfx/pyproject.toml.scripts/ci/update_pyproject_combined.py to patch pyproject.toml and src/backend/base/pyproject.toml with the new nightly version numbers and the langflow-nightly / langflow-base-nightly package names.uv lock in both workspace roots to regenerate lock files.The three tags are emitted as job outputs (main_tag, base_tag, lfx_tag) and consumed by all downstream jobs.
Nightly package name mapping:
| Stable package name | Nightly package name |
|---|---|
langflow | langflow-nightly |
langflow-base | langflow-base-nightly |
lfx | lfx-nightly |
Sources: .github/workflows/nightly_build.yml58-182
.github/workflows/nightly_build.yml184-266
After the tag is created, build-hash-history runs scripts/build_hash_history.py --nightly. This script:
src/lfx/src/lfx/_assets/nightly_hash_history.json (append-only; the script validates no existing entries are modified or removed).If the hash history file changed, the job:
nightly-hash-history-updates from main with only the hash history file changed.This branch is later used to create a PR back to main (see Hash History Merge).
Hash History File Flow
Sources: .github/workflows/nightly_build.yml184-266
.github/workflows/nightly_build.yml268-304
Tests run in parallel after create-nightly-tag:
frontend-tests: calls typescript_test.yml with release: true and tests_folder: "tests". This runs all tests tagged @release.backend-unit-tests: calls python_test.yml with all four Python versions (3.10, 3.11, 3.12, 3.13).If either test job fails, release-nightly-build is still attempted (the condition uses result != 'failure'), so a flaky test does not automatically skip publishing. However, if both fail the release job will not run.
Integration tests are intentionally excluded from the nightly gate due to third-party integration flakiness.
Sources: .github/workflows/nightly_build.yml268-304
.github/workflows/release_nightly.yml49-402
The release-nightly-build job calls release_nightly.yml with:
build_docker_base: truebuild_docker_main: truebuild_docker_ep: truebuild_lfx: truecreate-nightly-tagInside release_nightly.yml, packages are built in dependency order:
Package Build and Publish Order
Each build step:
langflow-nightly) and the version matches the nightly tag.uv build --wheel.Cross-platform installation tests (via cross-platform-test.yml) run across Linux AMD64, macOS AMD64, macOS ARM64, and Windows AMD64 on Python 3.10, 3.12, and 3.13 before any PyPI publishing.
Publishing uses uv publish with UV_PUBLISH_TOKEN set to the PYPI_API_TOKEN secret. The base package waits an additional 5 minutes after publishing before the main package is built, to allow PyPI propagation.
Sources: .github/workflows/release_nightly.yml49-402
.github/workflows/release_nightly.yml404-462
.github/workflows/docker-nightly-build.yml1-300
After the packages are built (but not necessarily after publish), Docker builds start in parallel for base and main release types. They are called via docker-nightly-build.yml.
Docker nightly image tag patterns:
| Image type | Docker Hub tag pattern | GHCR tag pattern |
|---|---|---|
| Nightly base | langflowai/langflow-nightly:base-{version}-{arch} | ghcr.io/langflow-ai/langflow-nightly:base-{version}-{arch} |
| Nightly main | langflowai/langflow-nightly:{version}-{arch} | ghcr.io/langflow-ai/langflow-nightly:{version}-{arch} |
| Nightly all | langflowai/langflow-all-nightly:{version}-{arch} | ghcr.io/langflow-ai/langflow-all-nightly:{version}-{arch} |
Docker builds run in a matrix of amd64 and arm64 architectures (using Langflow-runner and langflow-ai-arm64-40gb-ephemeral self-hosted runners). After per-architecture images are pushed, a manifest merge step combines them into a single multi-architecture image tag.
The version format for nightly Docker images is validated to match the pattern ^[0-9]+\.[0-9]+\.[0-9]+\.dev[0-9]+$.
The following Dockerfiles are used:
./docker/build_and_push_base.Dockerfile./docker/build_and_push.Dockerfile./docker/build_and_push_with_extras.Dockerfile./docker/build_and_push_ep.DockerfileSources: .github/workflows/release_nightly.yml404-462 .github/workflows/docker-nightly-build.yml44-300
.github/workflows/nightly_build.yml380-540
After release-nightly-build succeeds, merge-hash-history-to-main runs only when:
refs/heads/main (to prevent PRs from feature branches).build-hash-history succeeded.release-nightly-build succeeded.auto_merge_hash_history is true (default) or the trigger is a scheduled run.Steps:
nightly-hash-history-updates branch created by build-hash-history.src/lfx/src/lfx/_assets/nightly_hash_history.json was modified.nightly-hash-history-updates to main using gh pr create or gh pr edit.gh pr merge --auto --squash.Sources: .github/workflows/nightly_build.yml380-540
.github/workflows/nightly_build.yml324-378
slack-notification runs after all major jobs complete (always()), but only when:
release-nightly-build, frontend-tests, backend-unit-tests, merge-hash-history-to-main), ORrelease-nightly-build succeeded.On failure, the notification identifies which job failed and includes a link to the GitHub Actions run. The webhook URL is stored in secrets.LANGFLOW_ENG_SLACK_WEBHOOK_URL.
.github/workflows/ci.yml91-155 .github/workflows/ci.yml342-456
The ci.yml workflow, which runs on every pull request, includes a check-nightly-status job. This job queries the PyPI API for langflow-nightly and checks whether the latest version was uploaded today.
GET https://pypi.org/pypi/langflow-nightly/json
If the latest release date does not match today's UTC date, should-proceed is set to false.
The ci_success aggregation job then fails the entire CI run if:
should-proceed != 'true', ANDworkflow_dispatch, ANDThis means a broken nightly build blocks all PR merges until it is fixed. The gate can be bypassed by manually triggering CI with workflow_dispatch.
Nightly Status Gate Logic
Sources: .github/workflows/ci.yml91-155 .github/workflows/ci.yml342-456
When triggering the nightly build manually via workflow_dispatch, the following inputs are available:
| Input | Default | Description |
|---|---|---|
runs_on | ubuntu-latest | Runner selection |
skip_frontend_tests | false | Skip Playwright tests (testing only) |
skip_backend_tests | false | Skip pytest (testing only) |
skip_slack | false | Suppress Slack notification |
push_to_registry | true | Whether to push to PyPI and Docker registries |
auto_merge_hash_history | true | Whether to create the hash history PR |
Note: push_to_registry: true is incompatible with skip_frontend_tests: true or skip_backend_tests: true — the validate-inputs job will fail if this combination is attempted.
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.