Currently, our site contains the only IDE that helps you to write SQLX code, offering syntax highlighting and automatic code completion. We wanted to make sure that our open source community benefits from the same tools, and so today we're announcing the release of a SQLX extension for Visual Studio Code.
Features
SQLX
file syntax highlighting- Project compilation on save
Cmd + click
inside aref
function to view the referenced file

Installation:
- Install the Dataform CLI locally:
npm i -g @dataform/cli
- Download our extension here
- Open a project containing a SQLX file
- You'll see project compilation notifications each time you save a file
Our process:
(If you’re not interested in the details of how I developed the extension, then there's no need to read further. Otherwise, read on!)
I decided to make this extension as part of a hackweek project, during which we dedicate a week towards something different from our normal day jobs. In reality, this ended up taking two hackweeks to be ready for launch. Here is the final source code.
Highlighting:
Initially I just wanted to get syntax highlighting working. Fortunately we already had highlighting that worked out of the box, because we use the Monaco editor in our website IDE. So the main thing was to try to get an extension working in VS Code. For this, I largely followed the docs, which were pretty comprehensive.
One difference between us and the docs is that we use the Bazel build system instead of the standard webpack build. This just meant that I had to include some extra boilerplate to compile our typescript into javascript for the extension.
I simply created a folder containing the recommended start files (below) with some boilerplate code in extension.ts
and ran code --extensionDevelopmentPath: ./vscode
once I’d compiled my .ts
files.

This got me the syntax highlighting straight away!
Compiling:
Later, I realised that we could go a little further than simple syntax highlighting. In our web IDE, we compile the code you write on the fly and show you any errors in real-time. And in the context of the extension, we have access to your whole project. So we should be able to compile the whole thing in the same way.
However, this would require a more complicated VS Code extension. As I understand it, extensions have a Client and a Server architecture. At the time, I was just using the Client, which is fine for simple things like syntax highlighting. However, if I wanted to do things like interface with the user’s file system or suggest definitions, then I would need to use a Language Server. The server and client would communicate with each other by subscribing to events such as onRequest(“compile)
. So I took some more boilerplate, added it to my server.ts
, and managed to get some messages being sent between the client and server.
Then I was ready to implement the project compilation. There were two options I could’ve pursued. The first would be to rebuild a lot of what we already have inside our website backend and run the compilation step inside the language server. The second would be to run our open source CLI inside the language server as a simple terminal process, and save the result of that.
I chose the second option, as it was much easier to get started and I wouldn’t have to rebuild so much code. Fortunately, we already had code very similar to this elsewhere, so I was able to ~~copy~~ leverage much of the code from there. It ended up looking something like this:
connection.onRequest("compile", async () => {
const compileResult = await getProcessResult(exec("dataform compile --json"));
if (compileResult?.compilationError) {
connection.sendNotification("error", compilationError.message);
} else {
connection.sendNotification("success", "Project compiled successfully");
}
}
Definitions:
Once this was done, and I had compilation notifications popping up using VS Code’s notifications API, I realised that I could go further yet! Given the contents of a ref
function, and a compiled project, I should be able to determine the file name that the ref was referring to.
This required me using the Definitions API, which essentially requires you to create an onDefinition
handler in your server, and return a Definition object if the piece of code being requested has a valid definition. Once I ironed out a few bugs, the code looked roughly like this:
connection.onDefinition(
(params): HandlerResult<Location, void> => {
const linkedFileName = retrieveLinkedFileName(params.textDocument.uri);
const fileString = `${WORKSPACE_ROOT_FOLDER}/${linkedFileName}`;
return {
uri: fileString,
range: {
start: { line: 0, character: 0 },
end: { line: 1, character: 0 }
}
} as Location;
}
);
Publishing
Now I had syntax highlighting, compilation and jump-to-definition working and I decided to publish the first draft of the extension. Mostly this was as described in the docs. I used the vsce package to properly compile a .vsix
file ready to be used. There was a bit of work to get the bazel build putting the compiled code in the correct place, but once that was worked out I was able to install the package itself in my VS code extension library and verify that it worked.
The final step was creating an account in Azure, and uploading our extension to the VS Code extension library. I was pleased to see that the vsce package
command nicely cuts some details out of the package.json
and adds it to the extension library site:

And as a bonus, VS Code automatically detects that .SQLX
files have an extension now, and offers to show off our extension!

Conclusion
Hopefully I’ve given you a taste for VS Code extension development. If you’re interested in trying your own extension, I’d highly recommend it as being easy to get started and easy to distribute your code.
This extension is still in Alpha, and no doubt there will be various bugs. Please let us know if you find any and let us know what feature you’d like to see next!