# PRQL: a pipelined SQL replacement that compiles to SQL

> PRQL is a Rust compiler that turns a pipelined query language into SQL for any SQL database. It is usable today by the intrepid, but the README is explicit that bugs and feature gaps remain.

**PRQL/prql** — PRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement

- Repository: https://github.com/PRQL/prql
- Website: https://prql-lang.org
- Stars: 10,917 · Forks: 256
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/prql-prql

## The problem PRQL targets: SQL that reads bottom-up inside a pipeline

SQL is declarative and readable in small pieces, but a query with several stages of filtering, grouping and windowing has no order. The clauses are evaluated in a sequence the reader has to reconstruct, and there is no place to put a variable or a reusable function. PRQL's premise is that a query is a pipeline of transformations, and that each line should transform the result of the line above it. The README puts it plainly: "Unlike SQL, it forms a logical pipeline of transformations, and supports abstractions such as variables and functions."

The audience follows from that. It is for people who already write analytical SQL and want to stop repeating themselves: analysts with long dashboards, data engineers with transformation layers, and tool builders who want a query representation they can generate. It compiles to SQL, so the target database does not change. The README states it can be used with any database that uses SQL.

## How PRQL compiles: a Rust workspace with a parser, a compiler and bindings

The repository is a Cargo workspace. The members list shows the pieces: prqlc-parser, prqlc, prqlc-macros, and bindings for Elixir, Java, JavaScript, C and Python. The compiler itself is prqlc, and the bindings wrap it for other languages rather than reimplementing the language.

The data flow is a compile step, not a runtime. PRQL source is parsed, resolved and lowered into SQL text, which is then sent to whatever database client you already use. PRQL is not a query engine and does not execute anything. That is why the language can target Postgres, DuckDB or Snowflake without a per-database driver.

The pipeline semantics are visible in the README's larger example. filter replaces both WHERE and HAVING, which removes the mental split between pre-aggregation and post-aggregation filtering. Variables declared with derive can reference earlier variables, so gross_cost is defined in terms of gross_salary. group runs an inner pipeline over each group and aggregate reduces each group to a value. Range expressions appear in take 1..20, and the README notes take 20 is also valid. The escape hatch is the s-string: s"LEFT(country, 2)" embeds raw SQL when the language has not caught up.

## Installing the PRQL compiler and compiling a first query

The README does not give a package-manager install line for the CLI. It points to the website, the book, the playground and the language bindings, so the canonical starting point is https://prql-lang.org and the documentation at https://prql-lang.org/book. The playground at https://prql-lang.org/playground runs in the browser and needs no install, which is the fastest way to see the generated SQL before committing to anything.

For building from source, the workspace pins the toolchain through rust-toolchain.toml and the workspace manifest sets rust-version to 1.85.0. The README says the project "can be built in a couple of commands" and links the development documentation for the details. The workspace profile for release builds sets lto to true and opt-level to "s", so the binary is optimized for size rather than speed. The Cargo.toml comment explains the reasoning: the compiler is fast enough as it is, for now.

Once you have a compiler, a first query is a pipeline. The README's smallest example filters tracks by artist and aggregates three columns:

```elm
from tracks
filter artist == "Bob Marley"
aggregate {
  plays    = sum plays,
  longest  = max length,
  shortest = min length,
}
```

Each line transforms the previous result. The aggregate block reduces each column to a value, and the named assignments set the output column names. Trailing commas are allowed, which matters if you generate PRQL from another tool. What you should see after compiling is a single SQL SELECT with the filter in WHERE and the three aggregates in the select list.

The Python route is documented separately. The README links pyprql and a Jupyter magic that runs PRQL against a database, or against a Pandas DataFrame, CSV or Parquet file through DuckDB. That is the shortest path if your data already lives in a notebook.

## Where PRQL is the wrong tool right now

The README's status section is unusually candid for a project page, and it should be read before adoption. It says PRQL "still has some bugs and some missing features, and is probably only ready to be rolled out to non-technical teams for fairly simple queries." If your plan is to hand PRQL to business users as a self-service layer, that sentence is the answer.

Development has slowed. The README states the team is deciding how to work on a new resolver, which will let them squash many bugs and simplify the code, and that they are "increasingly open to contributions for bigger rewrites of the resolver given how bottlenecked we are on it." A resolver rewrite is the kind of change that can alter how ambiguous queries compile. The README does not document a compatibility or deprecation policy for generated SQL across such a change, and it does not document a rollback path for a query that compiles differently after an upgrade.

There is also an open question about the language's own decisions. The README links issue 2723 on how window functions are handled outside of a window transform, which means that part of the design is still under review. If your workload is window-function heavy, that is the specific thing to check against your queries before you rely on it. And the README notes that compiler contributions are concentrated in a small group, so a bug you hit may not be fixed on your schedule.

## PRQL compared with Malloy and EdgeQL

Malloy and EdgeQL are the alternatives that come up in the same searches, and they differ from PRQL in where the work happens.

PRQL is a compiler that emits SQL text. It has no runtime, no server and no storage. You keep your existing database, your existing driver and your existing execution path, and PRQL only replaces the authoring step. That is the whole trade: the output is portable across every SQL database, and the language is bounded by what SQL can express, which is why the s-string escape hatch exists.

Malloy is built around a semantic model that describes relationships between tables, so joins are inferred from the model rather than written out. That moves work from the query into a separate modeling artifact, and it means the tool owns more of the stack than a compiler does. EdgeQL belongs to a database with its own query engine, so it is not a path to your existing Postgres instance at all.

The practical difference for a team already on Postgres or Snowflake is that PRQL can be introduced one query at a time. Nothing about the database changes. A semantic-model tool asks you to describe your schema first, and a database-specific language asks you to move.

## Licence, releases and the cost of upgrading

PRQL is Apache-2.0, declared both in the repository and in the workspace package metadata. That is a permissive licence with an explicit patent grant, which is generally what a company wants for a tool embedded in its own pipeline. This is a description of the licence text, not legal advice; if PRQL ends up inside a distributed product, have counsel read the Apache-2.0 terms rather than this paragraph.

Upgrades are cheap to perform and expensive to verify. The compiler is a single binary or a language binding, so there is no server to migrate and no data to move. But the output is SQL, and a new compiler version can emit different SQL for the same source. The release cadence in the recent releases is regular: 0.13.12 in April 2026, 0.13.13 in June, 0.13.14 in July, and the workspace version at 0.13.15. The last push to the repository was on 2026-09-21.

Because the README does not document rollback or a compatibility guarantee for generated SQL, the verification step is yours. Keep the compiled SQL for your critical queries under version control, and diff it after each compiler bump. That turns an opaque upgrade into a reviewable one, and it is the only mechanism the project's own documentation leaves you.

## Integrations and where PRQL is heading

The README's integration list is short and specific: a VS Code extension, Jupyter integration, and QStudio, which the README links at timestored.com. The project's stated goal is to make starting easy by meeting people in tools they already use, and it asks readers to open an issue if they know of a tool that would be open to integrating.

The stated work items are worth reading as a roadmap. The team is resolving priority bugs, filling remaining feature gaps so that PRQL can express almost all standard SQL queries, and adding experimental support for modules and multi-file projects. That last item matters if you generate PRQL programmatically, because it implies the language is moving toward a unit larger than a single query.

There is also a contribution angle. The README points to issues labeled good first issue, a discussion thread at issue 1840 for feedback on making the compiler easier to contribute to, and a request to send use-cases. For a compiler with a concentrated contributor base, filing your use-case is not a courtesy; it is how the feature gaps that block you get prioritized.

## Conclusion

Adopt PRQL if your team already writes long analytical SQL and wants variables, functions and a readable pipeline, and if you can live with the bugs the README acknowledges. Do not adopt it for non-technical teams beyond fairly simple queries, and do not expect a stable resolver yet: development has slowed while a new one is designed. Before committing, compile your three longest existing queries with the CLI and compare the generated SQL against what you run today.

## FAQ

### What is PRQL and what does it compile to?

PRQL stands for Pipelined Relational Query Language and is pronounced "Prequel". It is a language for transforming data that compiles to SQL, so it can be used with any database that uses SQL. Each line in a PRQL query transforms the result of the line above it.

### How do I use PRQL with DuckDB or Postgres?

PRQL itself does not connect to a database; it compiles to SQL, which you then run through your existing client. The README documents a Jupyter magic that runs PRQL against a database, or against a Pandas DataFrame, CSV or Parquet file through DuckDB.

### Is there a Python binding for PRQL?

Yes. The repository includes a prqlc-python binding in the Cargo workspace, and the README links pyprql as the documentation for the Python bindings, including the Jupyter integration.

### Is PRQL ready for production use?

The README says PRQL is ready to use by the intrepid and that it still has some bugs and missing features. It adds that the language is probably only ready to be rolled out to non-technical teams for fairly simple queries.

## Sources

- [License: Apache-2.0](https://github.com/PRQL/prql/blob/main/LICENSE)
- [Project website](https://prql-lang.org)
- [PRQL/prql on GitHub](https://github.com/PRQL/prql)
- [README](https://github.com/PRQL/prql/blob/main/README.md)
- [Releases](https://github.com/PRQL/prql/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/prql-prql
