Send Feedback
Skip to content

How to Develop Scripts

This page details how to write, load, and manage q scripts to build reusable, maintainable code.

Scripts are text files containing code that allow you to capture interactive commands and define functions as reusable code.

Use scripts to achieve many things, such as:

  • Create reusable code, distribute it easily, and use it as building blocks for an application.
  • Adapt KDB-X to serve as real-time databases (RDB), historical databases (HDB), client gateways, analytics schedulers, and more.

Tip

The .q file extension is used to denote scripts containing q code. KDB-X also processes k code, which uses the .k file extension.

To edit scripts, use your favorite editor such as Vim, Emacs, Visual Studio, and many others.

Overview

Load scripts

Load scripts at different times, either at startup or during run time; or define a script to load another script.

Startup

For KDB-X to execute a script at startup, pass its filename as the first command-line parameter to the q executable. For example:

$ q testscript.q

Provide any command-line parameter(s) required after the script name, not before.
For example, to load/execute the script testscript.q while enabling quiet mode:

$ q testscript.q -q

Run time

To load scripts at run time, use the system command \l. For example:

q)\l test.q

Refer to scripts using absolute or relative paths. If no path is provided and the script isn't in the current directory, KDB-X looks in the directory specified by the QHOME environment variable.

Using the q language, you may also dynamically construct the path to a script before loading it. The example below demonstrates an alternative approach where the script path is built from an environment variable (retrieved using getenv).

q)system "l ",getenv[`TMPTEST],"/tmptest.q"

Scripts loading scripts

Because scripts execute as q code, one script may load another. This is useful to reuse common code across multiple scripts. For example, the contents of a script myscript.q could load multiple scripts:

\l utils.q
\l common.q

/  code goes here

Loading once

You might need to run or initialize a script once. Loading the same script multiple times can cause issues, especially when it defines shared variables, functions, or state.

The example below shows a script, test.q, that defines variables but protects them from being re-initialized by checking whether the script has already been loaded.

It uses a namespace (.myscript) and checks for the existence of a key (version) before running the initialization block:

-1"Loading script";
if[not `version in key `.myscript;
  -1"Running code once";
  .myscript.version:22;
  / further code to be executed once goes here
  ]

When you load this script multiple times, the protected block executes once, preventing duplicate setup or state definition.

q)\l test.q
Loading script
Running code once
q)\l test.q
Loading script
q)\l test.q
Loading script

Write scripts

Script execution

The following example script (basic.q), uses -1 to print information displaying the order of execution. It creates a variable to show it's accessible after the script runs and creates a function that is called after the script is loaded.

-1"first line";
a:33
myfunc:{x+x}
-1"last line";

KDB-X executes scripts as it loads them, from top to bottom. When you load a script, it prints each line in order, creates the variable and function, and makes them available for use after execution:

q)\l basic.q
first line
last line
q)a
33
q)myfunc[22]
44

Run scripts with bad syntax

If KDB-X encounters incorrect code in a script, it immediately throws an error and stops processing the rest of the script. The following bad.q contains a syntax error on the second line:

-1"about to run some bad code";
bad_code_here
-1"running after bad code";

Loading the script shows that the following line(s) after the bad code is not executed. Debug information is printed on where the error occurred and execution is suspended.

To abort the suspended function and return to the normal q session, use \:

q)\l bad.q
about to run some bad code
'bad_code_here
  [3]  /private/tmp/bad.q:2: bad_code_here
                             ^
q))\
q)

Printing strings to an output is useful for logging. You can print strings to stdout, stderr or files using the relevant file handles.

For example, output.q:

-1 "this prints with a return character appended to stdout";
-2 "this prints with a return character appended to stderr";
1 "this prints without a return character appended to stdout";

Running the script prints:

q)\l output.q
this prints with a return character appended to stdout
this prints with a return character appended to stderr
this prints without a return character appended to stdoutq)

Use -1 to print a list of strings, followed by .z.P to get the current local time and .Q.s1 to format data as a string:

-1 "Current time ",.Q.s1 .z.P;

Running the script prints the current time:

q)\l output.q
Current time 2025.05.28D11:29:57.452093632

Avoid name clashes

When developing reusable code in scripts, ensure the script does not overwrite or alter code that exists outside its scope. Other languages address this using constructs like Java package naming, C++ namespaces, and Python modules. q provides similar isolation using custom namespaces, which allow you to encapsulate variables and functions.

Warning

Avoid using single-character namespaces, as they are reserved for KX system use.

Refer to a namespace to create it. The following script test.q creates code within .mycode:

.mycode.myvar:22
.mycode.myfunc:{.mycode.myvar+x}

Loading the script shows that the functions have been created within the .mycode namespace. Outside its containing namespace, an object is known by the full name of its containing namespace followed by a dot and its own name.

q)\l test.q
q).mycode.myfunc[22]
44

As namespaces are implemented as dictionaries, view their contents by entering the namespace name:

q).mycode
      | ::
myvar | 22
myfunc| {.mycode.myvar+x}

Tip

Namespaces can contain other namespaces.

Use the system command \d to set the current namespace. The following script test.q creates code within the .mycode namespace before returning to the root namespace at the end:

\d .mycode
myvar:22
myfunc:{myvar+x}
\d .

Loading the script shows that the functions have been created within the .mycode namespace:

q)\l test.q
q).mycode.myfunc[22]
44

Tip

Using modules is another way to avoid name clashes between different source files.

Multiline expressions

Scripts let you split long expressions across multiple lines to improve readability or avoid exceeding the maximum line length. Continuation lines must be contiguous (no empty lines between them) and indented with one or more spaces. For example:

jt:.[!] flip(
  (`first; "Jacques");
  (`family; "Tati");
  (`dob; 1907.10.09);
  (`dod; 1982.11.05);
  (`spouse; "Micheline Winter");
  (`children; 3);
  (`pic; "https://en.wikipedia.org/wiki/Jacques_Tati#/media/File:Jacques_Tati.jpg") )

portrait:{
  n:" "sv x`first`family;                / name
  i:.h.htac[`img;`alt`href!(n;x`pic);""]; / img
  a:"age ",string .[-;jt`dod`dob]div 365; / age
  c:", "sv(n;"d. ",4#string x`dod;a);     / caption
  i,"<br>",.h.htac[`p;.[!]enlist each(`style;"font-style:italic");c] }

Comments

In a q session, add comments by prefixing a line or statement with /, as shown below:

a:22 / this is a comment

Comments in scripts offer greater flexibility compared to interactive q sessions.

Multiline comments

Include comments that span multiple lines by starting the block with a forward slash (/) and ending it with a backslash (\):

/
  This is a comment block.
  Q ignores everything in it.

  And I mean everything.
  2+2
\

Trailing multiline comments

When closing a comment block, using a line with a single backslash (\) starts a trailing comment block, causing the interpreter to ignore all subsequent lines. There is no way to terminate a trailing comment block once it begins.

In the example below, the expressions that call the main and exit functions are placed after a trailing comment block. This prevents them from executing immediately, allowing the script to load while keeping the environment available for exploration.

foo:42
bar:"quick brown fox"
main:{x,y}

\
main[foo;bar]
exit 0

Script information

Sometimes you need to inspect the scripts to find some information.

Retrieve the name of initial script

Use .z.f within a script to retrieve the name of the script that was passed to q on the command line. For example, myscript.q containing -1"Executing script ",string .z.f; would print the following when loaded:

$ q myscript.q -q
Executing script myscript.q"

Use value to find information on functions

Use value to inspect functions, including where they have been defined. For example, a function f that was created when loading script /private/tmp/test.q would show:

q)value f
0x6261410003
`x`y
`symbol$|()
,`
5 3 4 2 2
"..f"
"/private/tmp/test.q"
1
"{x+y}"

Use index notation to view the sixth element (the element number depends on the function, it is the third element counting from the end) and the name of the script where it was previously defined:

q)value[f]6
"/private/tmp/test.q"

Run as a shebang script

It is common practice to load a script into q, as described earlier.

If you need to create a standalone executable that runs KDB-X with a script, execute it as a shebang:

$ more ./test.q
#!/usr/bin/env q
2+3
\\

$ chmod +x ./test.q

$ ./test.q
KDB-X 5.0.20251113 2025.11.13 Copyright (C) 1993-2025 Kx Systems
...
5

Hide your code

You may need to distribute code without exposing the source. Use the system command \_ to hide or protect parts of the script from being viewed.

For example, using a script called hide.q containing a function and a variable:

hiddenFunc:{val+x+y};
val:55;

Anyone with access to hide.q can open the file to read its contents or inspect the code at run time. Retrieve information about functions using value. For example:

q)\l hide.q
q)hiddenFunc
{val+x+y}
q)value hiddenFunc
0x62614181410003
`x`y
`symbol$|()
``val
24 22 23 12 21 11 11
"..hiddenFunc"
"/private/tmp/hide.q"
1
"{hiddenVal+x+y}"

Create a new file from the existing script. By default, the filename uses a trailing underscore to indicate the version with hidden code:

q)\_ hide.q
`hide.q_

Warning

Do not delete the original file if you wish to retain the source code.

You can now distribute the new hidden version. Viewing the contents of the file no longer shows the source code:

$ cat hide.q_ 
6???fc?G6????k

Loading the hidden file prevents the user from viewing the source code:

q)\l hide.q_
q)hiddenFunc
locked
q)value hiddenFunc
`byte$|()
`x`y
`symbol$|()
,`
`long$|()
"..hiddenFunc"
""
-1
"locked"

The functions remain callable and behave as expected:

q)hiddenFunc[2;5]
62

Although the functions are hidden, you can still redefine them:

q)hiddenFunc[2;5]
62
q)val:0
q)hiddenFunc[2;5]
7
q)hiddenFunc:{y-x}
q)hiddenFunc[2;5]
3

Summary

In this guide, you learned how to:

  • Define and load q scripts at startup and run time
  • Organize code with nested loads and namespaces
  • Protect one-time initialization blocks
  • Handle errors, print logs, and inspect metadata
  • Leverage comments, multi-line syntax, and shebang execution
  • Hide code for safe distribution

Next steps

  • Build a reusable utility library and package it for team use
  • Automate scheduled jobs with q scripts and cron integration
  • Explore advanced error-handling patterns (.Q.err)

Feel free to refer back as you develop robust, maintainable q applications.