Crazy Idea to Postgres in the Browser
We just launched our Postgres Playground. Running Postgres in the web browser was not exactly commonplace before, so naturally, people are wondering how it works.
It actually started as a fun weekend experiment. Here's a screenshot I saved, just moments after recovering from the initial "whoa, it's working!" effect.
The next morning, I shared this screenshot in our internal Slack channel for web frontend engineering. Our mental gears began to turn as we imagined what might (and might not) be possible. After a bit of work, we built upon some interesting ideas, and this fun weekend hack evolved into what is now the Postgres Playground!
This blog post focuses on how to run PostgreSQL in the web browser, but there are other interesting pieces involved in the playground as well. For example, the content in the tutorials actually lives in Notion documents. There may be a blog post about that in the near future from one of my colleagues, so stay tuned!
Why?
I stumbled upon an interesting blog post about how Wasmer has a "Run in Playground" link for some Markdown fenced code blocks for a few of their WAPM packages. There was one in particular that really got my attention: SQLite. On that page, there is a fenced code block with some SQL queries inside. If you click the "Run in Playground" button, it runs the query right there in the web browser with SQLite compiled to WebAssembly.
After running that SQLite query in my browser, I thought, "Can I do this with Postgres?".
The modern web browser is a very powerful platform, and this platform's capabilities are constantly increasing. However, WebAssembly still has some growing to do in some areas. After some quick research, I found that the web browser simply does not offer the networking features that Postgres needs. That would seem like a pretty big obstacle.
However...
As I mentioned, the modern web browser is a very powerful platform. Let's just change the target platform to something other than WebAssembly, then run it in WebAssembly anyway like a rebel. 😎
Virtual machines in the browser
It's actually possible to emulate a PC inside the web browser! There have been quite a few implementations over the years. Some even started out in JavaScript, years before WebAssembly was an option. Here are a few that I found especially interesting:
Emulator | Architecture |
---|---|
Halfix | x86 |
JSLinux | x86 and RISC-V |
jor1k | OpenRISC 1000 |
v86 | x86 |
WebVM | x86 |
I ended up choosing v86 for this. The author started the project in 2011, and it's still active. Many questions have been answered in the GitHub issues and discussions over the years. I'm definitely not an expert in Linux or virtualization, so being able to search the repo for answers was very helpful.
v86's performance also seemed to be among the best, compared to similar open source emulators that run in the browser. In early 2021, they merged a Rust port + JIT into the master branch, which provided a significant performance boost over the original JavaScript implementation.
Build
For this blog post, we'll use Alpine Linux. It's a lightweight Linux distribution and a very popular base for many Docker images. They also have a version with a slimmed-down kernel, optimized for virtual machines.
Install Alpine Linux
Note: You'll need to have QEMU installed.
Download the Alpine image that is optimized for VMs. We'll need the x86 (not x86_64) build.
wget https://dl-cdn.alpinelinux.org/alpine/v3.16/releases/x86/alpine-virt-3.16.0-x86.iso
Create a disk image for the VM. I chose my disk size somewhat randomly, so feel free to make it larger if you'd like. You could probably make it smaller, but I'm not sure what the minimum size limit would be here.
qemu-img create alpine.img 512M
Start the VM
qemu-system-x86_64 \
-m 256M \
-cdrom alpine-virt-3.16.0-x86.iso \
-drive file=alpine.img,format=raw
Note: Depending on your host machine, you may be able to get a performance boost by appending another argument to the command:
Host machine | Argument |
---|---|
Linux with x86 CPU | -accel kvm |
macOS with x86 (Intel) CPU | -accel hvf |
macOS with Apple Silicon | None, but your CPU is a beast anyway. |
When the VM has finished booting, log in as 'root'.
Run setup-alpine
. For most of the setup questions, you can configure things to your liking, but these are important:
Question | Answer |
---|---|
Which disk(s) would you like to use? | sda |
How would you like to use it? | sys |
WARNING: Erase the above disk(s) and continue? | y |
After the installation has finished, use the reboot
command to reboot the VM from the virtual hard disk image.
Install Postgres
After the VM has rebooted, log in as root
again. We can now install and initialize Postgres.
apk add postgresql --no-cache
/etc/init.d/postgresql setup
/etc/init.d/postgresql start
rc-update add postgresql
Now, a quick smoke test:
su - postgres -c 'psql -c "SELECT version();"'
If it worked, you should see something like this:
version
----------------------------------------------------------------------------------------------------------------
PostgreSQL 14.4 on i586-alpine-linux-musl, compiled by gcc (Alpine 11.2.1_git20220219) 11.2.1 20220219, 32-bit
(1 row)
Note: On my machine, psql
opened the version information in less
, so I had to press q
to exit that.
Now we can shut down the VM.
poweroff
Run the VM in the web browser
- Go to v86's site.
- Scroll down to the "Setup" section.
- For "Hard disk drive image", select the
alpine.img
file you created earlier. - Adjust "Memory size" to your liking. (I used 256 MB)
- Click the "Start Emulation" button.
Note: It will take a bit longer for the VM to boot. Running the VM in the web browser will not be as fast as it was in QEMU.
After it has finished booting, log in as root, then open psql
:
su - postgres -c psql
Congratulations! You are now running Postgres in your web browser.
Things to keep in mind:
- There is no internet access from inside the VM.
- There is no data persistence, so changes are lost when leaving or refreshing the page.
Related Articles
- Postgres Partitioning with a Default Partition
16 min read
- Iceberg ahead! Analyzing Shipping Data in Postgres
8 min read
- PostGIS Day 2024 Summary
8 min read
- Crunchy Data Warehouse: Postgres with Iceberg for High Performance Analytics
8 min read
- Loading the World! OpenStreetMap Import In Under 4 Hours
6 min read