Back to Prefect

Develop on Prefect

docs/contribute/dev-contribute.mdx

3.7.810.6 KB
Original Source

import fork from '/snippets/fork.mdx'

Make a code contribution

We welcome all forms of contributions to Prefect, whether it's small typo fixes in our documentation, bug fixes or feature enhancements! If this is your first time making an open source contribution we will be glad to work with you and help you get up to speed.

<Note> For small changes such as typo fixes you can simply open a pull request - we typically review small changes like these within the day. For larger changes including all bug fixes, we ask that you first open [an issue](https://github.com/PrefectHQ/prefect/issues) or comment on the issue that you are planning to work on. </Note>

Design principles

Prefect contributions should serve the project and its users, not just the immediate implementation request. We evaluate code, documentation, and issue proposals against these principles:

  • User-centered: Changes should solve a real workflow orchestration need for Prefect users and explain the user-facing value.
  • Correct and reliable: Prefer behavior that is explicit, deterministic, observable, and safe under failure.
  • Minimal and focused: Keep changes scoped to one clear problem and avoid broad rewrites or new abstractions without a strong reason.
  • Consistent with Prefect's architecture: Follow existing public APIs, orchestration boundaries, async patterns, settings behavior, and integration conventions.
  • Well-tested and documented: Cover meaningful behavior with tests and update documentation when users need to understand new or changed behavior.

Pull requests that make Prefect harder to reason about, broaden maintenance burden without clear user value, or bypass established architecture may be rejected even if the implementation works locally.

Issue first, code second

For anything larger than a small documentation or typo fix, open an issue or join the existing issue before opening a pull request. Issues give maintainers and contributors a place to confirm the problem, discuss scope, identify architectural constraints, and decide whether the change belongs in Prefect. An open issue is not automatically an invitation to open a pull request. Some issues require maintainer ownership because they touch architecture, product direction, compatibility, security, or release planning.

Use the issue discussion to narrow the work before writing code. For complex issues, propose a detailed approach and wait for a maintainer to confirm that the approach and contributor ownership are appropriate before submitting a pull request. A pull request is not the best place to discover that a feature does not fit the project, duplicates existing behavior, or requires a different design.

Using AI tools responsibly

You may use AI tools to explore the codebase, draft documentation, sketch tests, refactor code, or review your own work. You are responsible for every issue, pull request, and comment you submit. Treat AI output as a starting point, not as evidence that a change is correct.

Before opening an issue or pull request:

  • Reproduce the behavior yourself and include a minimal reproducible example for bugs when possible.
  • Keep each pull request focused on one bug fix, feature, or documentation improvement.
  • Explain the user-facing problem, why your approach fits Prefect's existing architecture, and any tradeoffs.
  • Run the relevant checks locally and include behavior-focused tests for code changes.
  • Update documentation when your change affects user-facing behavior.

Maintainers may close issues without further triage when they appear low-effort, unverified, likely AI-generated and lacking concrete detail, too broad, difficult to follow, or primarily shift investigation and validation onto maintainers. Maintainers may ask for pull request revisions for the same reasons, or close pull requests that appear low-effort, likely AI-generated, and substantially far from the expected implementation. This applies whether or not AI tools were used.

What maintainers look for

Reviews focus on whether the change should become part of Prefect and whether it can be maintained over time. The strongest pull requests:

  • Solve a clear user problem with enough context for reviewers to understand the value.
  • Fit Prefect's existing architecture, public APIs, and compatibility expectations.
  • Prefer clear, idiomatic code over cleverness, excessive abstraction, or broad rewrites.
  • Include tests that protect behavior instead of mirroring private implementation details.
  • Update documentation for user-facing behavior changes, or explain why documentation is not needed.
  • Explain meaningful tradeoffs, migration concerns, or follow-up work in the pull request description.

Even working code may need revision if it is difficult to reason about, overengineered, inconsistent with established patterns, or likely to create maintenance burden out of proportion to the user value.

Fork the repository

<fork />

Install Prefect for development

Once you have cloned your fork of the repo you can install an editable version of Prefect for quick iteration.

We recommend using uv for dependency management when developing. Refer to the uv docs for installation instructions.

To set up a virtual environment and install a development version of prefect: <CodeGroup>

bash
uv sync
bash
python -m venv .venv
source .venv/bin/activate

# Installs the package with development dependencies
pip install --group dev -e .
</CodeGroup>

To verify prefect was installed correctly:

<CodeGroup> ```bash uv uv run prefect --version ``` ```bash pip and venv prefect --version ``` </CodeGroup>

To ensure your changes comply with our linting policies, set up pre-commit and pre-push hooks to run with every commit:

bash
uv run pre-commit install

To manually run the pre-commit hooks against all files:

bash
uv run pre-commit run --all-files

To manually run the pre-push hooks:

bash
uv run pre-commit run --hook-stage pre-push --all-files
<Tip> If you're using `uv`, you can run commands with the project's dependencies by prefixing the command with `uv run`. </Tip>

Write tests

Prefect relies on unit testing to ensure proposed changes don't negatively impact any functionality. For all code changes, including bug fixes, we ask that you write at least one corresponding test. One rule of thumb - especially for bug fixes - is that you should write a test that fails prior to your changes and passes with your changes. This ensures the test will fail and prevent the bug from resurfacing if other changes are made in the future. Prefer tests that assert user-visible behavior or public contracts instead of private implementation details. All tests can be found in the tests/ directory of the repository.

You can run the test suite with pytest:

bash
# run all tests
pytest tests

# run a specific file
pytest tests/test_flows.py

# run all tests that match a pattern
pytest tests/test_tasks.py -k cache_policy

Submit your pull request

Before submitting a pull request:

  • Confirm the related issue is linked, unless the change is a small documentation or typo fix.
  • Keep the scope to one feature, bug fix, or documentation improvement.
  • Describe the problem, the approach, and any tradeoffs or alternatives considered.
  • Run the relevant tests and checks locally.
  • Add or update documentation for user-facing behavior changes.

The code shows what changed. The pull request description should explain why the change is useful and why this approach is appropriate for Prefect.

Working with a development UI

If you plan to use the UI during development, you will need to build a development version of the UI first.

Using the Prefect UI in development requires installation of npm. We recommend using nvm to manage Node.js versions. Once installed, run nvm use from the root of the Prefect repository to initialize the proper version of npm and node.

Start a development UI that reloads on code changes:

bash
prefect dev ui

This command is most useful if you are working directly on the UI codebase.

Alternatively, you can build a static UI that will be served when running prefect server start:

bash
prefect dev build-ui

Working with a development server

The Prefect CLI provides several helpful commands to aid development of server-side changes.

You can start all services with hot-reloading on code changes (note that this requires installation of UI dependencies):

bash
prefect dev start

Start a Prefect API that reloads on code changes:

bash
prefect dev api

Add database migrations

If your code changes necessitate modifications to a database table, first update the SQLAlchemy model in src/prefect/server/database/orm_models.py.

For example, to add a new column to the flow_run table, add a new column to the FlowRun model:

python
# src/prefect/server/database/orm_models.py

class FlowRun(Run):
    """SQLAlchemy model of a flow run."""
    ...
    new_column: Mapped[Union[str, None]] = mapped_column(sa.String, nullable=True) # <-- add this line

Next, generate new migration files. Generate a new migration file for each database type.

Migrations are generated for whichever database type PREFECT_SERVER_DATABASE_CONNECTION_URL is set to. See how to set the database connection URL for each database type.

To generate a new migration file, run:

bash
prefect server database revision --autogenerate -m "<migration name>"

Make the migration name brief but descriptive. For example:

  • add_flow_run_new_column
  • add_flow_run_new_column_idx
  • rename_flow_run_old_column_to_new_column

The --autogenerate flag automatically generates a migration file based on the changes to the models.

<Warning> **Always inspect the output of `--autogenerate`**

--autogenerate generates a migration file based on the changes to the models. However, it is not perfect. Check the file to ensure it only includes the desired changes. </Warning>

The new migration is in the src/prefect/server/database/migrations/versions/ directory. Each database type has its own subdirectory. For example, the SQLite migrations are stored in src/prefect/server/database/migrations/versions/sqlite/.

After inspecting the migration file, apply the migration to the database by running:

bash
prefect server database upgrade -y

After successfully creating migrations for all database types, update MIGRATION-NOTES.md to document the changes.