Skip to content


Folders and files

Last commit message
Last commit date

Latest commit



84 Commits

Repository files navigation


See everything happening in your running Django app. All without leaving VSCode

status: beta vscode downloads vscode last updated Chat on Discord

vscode extension version PyPI version

supported python versions supported django versions

Kolo is in beta so there's a chance that you will encounter a problem or bug. When you do, please open an issue on this repository and we'll look into it πŸ™

Annotated Kolo screenshot

DjangoCon Announcement video

Kolo launched at DjangoCon Europe 2021


Kolo consists of a Python package and a VSCode extension:

New & Noteworthy features

  • The frame visualization now includes a ✨ beautiful ✨ flame graph that shows timing information for each function call ⏱️

  • Show which line of your code caused Django execute a SQL query

  • Significantly simpler Kolo setup if you use Docker for local Django development

  • Support for custom request descriptions so that you can easily distinguish different requests even if they arrive at the same path

  • Much improved support for ✨ exceptions ✨ Jump straight to where the problem occurred and see the all the contextual information to understand why it happened


  1. Install the python package using
pip install kolo
  1. Add Kolo to the top of your MIDDLEWARE in :
  1. Make sure DEBUG is True in your file, then start your local Django server the way you normally would (for example: python runserver)
  2. Install the VSCode extension:
    • Kolo will show up with an icon in the left sidebar in VSCode
    • After clicking on the Kolo icon and opening Kolo within VSCode, follow the instructions to login and confirm your email
  3. Any new requests that get served by your local, running Django app will now show up in VSCode πŸŽ‰
    • Make your Django app serve an HTTP request (for example by going to localhost:8000), then return to Kolo in VSCode to inspect it πŸ”Ž πŸ™Œ

Minimum requirements

  • VSCode version 1.56 (released April 2021) or newer
  • Python 3.6 or newer
  • Django 2.2 or newer
  • git (Kolo requires git to accurately show line information in VSCode)


Kolo supports Docker for local Django development. In many cases, no additional configuration is required for Kolo to work.

Kolo relies on a volume definition to your working directory, which most projects already have configured. If your project does not yet have this configured, then you will need to set this up in order for Kolo to work.

So for example, in your Dockerfile you might have something like this specified:

COPY . ./

And then in your docker-compose.yml file, you will need the following corresponding volume definition:

    - .:/code

Kolo works by writing data to a sqlite database from within your running Django app. This volume definition ensures that the db.sqlite3 file that Kolo stores in the .kolo directory is stored not just inside Docker but also on your host operating system, where it can then be read by the Kolo VSCode extension.


Kolo only runs when DEBUG is set to True in your file. If you would like to disable Kolo when DEBUG is True, you can set the KOLO_DISABLE environment variable: KOLO_DISABLE=true

Path To Kolo Directory

If your VSCode workspace folder doesn't contain the file (and the adjacent automatically generated .kolo directory) at the top level, then you will need to set the "Path To Kolo Directory" setting in VSCode:

path to kolo directory setting VSCode

For example, you might have a top level VSCode workspace called "myproject" which has a backend folder that contains your Django app. If backend is the folder that includes your file and the .kolo directory, then the setting you need to set here is: backend


If you don't start your Django app using python runserver, you can make use of the KOLO_PATH environment variable to determine the path where Kolo should create the .kolo directory. Set KOLO_PATH like any other environment variable that your Django app makes use of.


You can specify request paths to be ignored via the .kolo/config.toml file:

# .kolo/config.toml

# Kolo will ignore all requests that include /static/ in their path
ignore_request_paths = ["/static/"]

If you would like to explicitly include or ignore certain frames, you can also do that:

# .kolo/config.toml

# Kolo will include all frames from the requests library, since each frame's file path would contain /requests/
include_frames = ["/requests/"]

# Kolo will ignore all frames from internal/
# This would be useful if does a lot of function calls that you don't particularly care about
ignore_frames = ["internal/"]

By default, Kolo expects the .kolo directory to be at the same folder level as your file, but you can specify a custom location for the .kolo directory via the KOLO_PATH environment variable

Custom request description and custom request body formatting

In some cases, just seeing the path of the HTTP request in the sidebar is not sufficient for identifying a request. Say, for example, that your Django app is processing webhook events from Stripe. All those events will arrive at the same path in your app, making it difficult to distinguish different types of events.

The request-body.js and request-description.js files are here to help us with this!

By default, a set of webhook events from Stripe will look like this:

But if we have the following JavaScript code in our .kolo/request-description.js file:

(function () {
  if (
  ) {
    parsed_body = JSON.parse(request.body)
    return {
      description: parsed_body.type

Then, Kolo will show the Stripe event type for each request, making it much easier to distinguish between the different payloads we received from Stripe πŸŽ‰


Within .kolo/request-description.js, a global request variable is available. The following fields exist on this variable:

  scheme: string;
  body: string;
  method: string;
  path_info: string;
  headers: {
    [key: string]: string;

Kolo expects an object with a top level description key to be returned in request-description.js, the value of which must be a string. So for example:

return {
  description: "my custom description"

If you would like to explicitly not have a description for a request, you can return undefined


request-body.js is a useful tool when you'd like to reshape the arriving request body purely for display purposes within Kolo. The code in .kolo/request-body.js executes before request-description.js meaning that your custom request description code can take adavantage of the reshaped body.

For example, some of the requests a Slack app might receive from Slack have a somewhat unusual format: Slack sends the request with the x-www-form-urlencoded content type containing only a single key called "payload" which then contains a JSON string of the actual payload. This request body can be a bit unwieldy, it would be more convenient to directly interact with the JSON payload. This is exactly what request-body.js can help us achieve.

The following .kolo/request-body.js code converts the payload to just regular JSON for display within Kolo:

(function () {
  if (request.body.startsWith("payload=") && request.headers["User-Agent"].includes("Slackbot")) {
    let request_body;
    try {
      request_body = decodeURIComponent(request.body);
    } catch (err) {
      request_body = request.body;
    const unparsed = request_body.replace("payload=", "");
    const parsed_json_body = JSON.parse(unparsed);

    return {
      body: JSON.stringify(parsed_json_body, null, 2),
      language: "json"

Within .kolo/request-body.js, a global request variable is available. The following fields exist on this variable:

  scheme: string;
  body: string;
  method: string;
  path_info: string;
  headers: {
    [key: string]: string;

Kolo expects an object with a top level body key to be returned in request-body.js, the value of which must be a string:

return {
  body: "my custom body",

You may also optionally pass a language key alongside body, which Kolo will pass along to VSCode when viewind the body.

If you would like to explicitly not have a custom request body for a request, you can return undefined


In VSCode, Kolo is available via the sidebar menu. Once clicked, Kolo shows the requests that your Django app recently served:

From this view you can start exploring your requests and what happened within them. Almost every item in this list is expandable, clickable, and will let you dig into the details

Inline annotations

To enable the inline code annotations for a specific request, click on the top level item in the list of recent requests. You should see a little confirmation message pop up, and then your code will be annotated with inline function arguments, return values, and local variables.

Frame visualization

Click on "Frames" for a specific request, and the frame visualization will open up

Check out for more feature screenshots ✨


During installation, Kolo confirms your email address. This is the only time any information is transmitted from the Kolo VSCode extension to our servers (only your email address is transmitted). Everything else such as your code, or any runtime data stays on your machine and is not transmitted anywhere.

The data Kolo collects at runtime is stored in a local SQLite database on your machine. This same SQLite database is then accessed by the VSCode extension to power all of Kolo's functionality.


Running into problems? Kolo is in beta, so it's possible you will run into a problem. When you do, please open an issue on this repository or email us:

Looking for assistance? We're here to help get Kolo set up on your codebase: Schedule Kolo set up