Let’s get to know Pkl by discussing some of its concepts and features.


Configuration tends to grow larger and more complex over time, making it increasingly difficult to understand and maintain. Pkl can reduce the size and complexity of configuration by

  • describing similar configuration elements in terms of their differences

  • introducing abstractions for common configuration elements

  • separating configuration structure from configuration data

  • computing instead of enumerating configuration


Pkl code lives in modules, a more fancy and general term for files. Evaluating a module produces an in-memory data model that is roughly comparable to a JSON data model. If evaluation completes successfully, the Pkl evaluator converts the data model to an external representation and terminates with the status code zero. Otherwise, the evaluator prints an error message and terminates with a non-zero status code.


All Pkl data is immutable. Manipulating a value always returns a new value, leaving the original value unchanged. Immutability eliminates many potential sources of errors.


Evaluation of Pkl code is strictly sandboxed. Except for a few well-defined and well-controlled exceptions, Pkl code cannot interact with the outside world. Leaving aside bugs in the language implementation, the worst thing that buggy or malicious Pkl code can do is to consume CPU and memory resources until the evaluator gets killed. Over time, sandboxing will be further strengthened to cover fine-grained CPU and memory boxing.


Converting a data model to an external representation is called rendering the model. Pkl ships with renderers for the following data formats:

  • JSON

  • Jsonnet

  • Pcf (a static subset of Pkl)

  • (Java) Properties

  • Property List

  • XML

  • YAML

Support for other formats can be added by writing a custom renderer in Pkl or Java. See Module Output and Value Visitor for more information.


By design, Pkl code tends to structurally and visually resemble the configuration it generates. This makes the code easier to read and write.


Modules can reuse other modules by importing them from local or remote locations. Imports can also be used to split up one large module into multiple smaller ones, increasing maintainability. A configurable security policy helps to keep imports under control.


Configuration is structured data. Pkl supports — but does not require — to express this structure as a configuration schema, a set of classes defining configuration properties, their defaults, types, and constraints. Writing and maintaining a configuration schema takes some effort but, in return, provides these benefits:

  • Independent evolution of configuration schema and configuration data, often by different teams (for example service providers and service consumers).

  • Automatic documentation generation.

  • Strong validation of configuration, both during development time and runtime.

  • Statically typed access to configuration from Java and other languages through code generation.

  • Schema-aware development tools, for example REPLs and editors with code completion support.


Pkl supports writing templates for objects and entire modules. Templates can be repeatedly turned into concrete configuration by filling in the blanks, and — when necessary — overriding defaults. Sharing template modules over the network can streamline complex configuration tasks for entire teams, organizations, and communities.


Everybody needs a configuration solution, but nobody wants to spend a lot of time learning it. To reflect this reality, Pkl has a strong focus on usability. For example, error messages explain causes and possible solutions and object properties maintain definition order to avoid surprises. We hope that this focus on usability will make Pkl accessible to a wide audience of occasional users, while still leaving room for expert users and advanced use cases.