DEV Community

Cover image for How I Built a Real-Time, Google Docs-like browser IDE for Python (and it's free!)
Jawad Rizvi
Jawad Rizvi

Posted on

How I Built a Real-Time, Google Docs-like browser IDE for Python (and it's free!)

For the past months, I’ve been building PyTogether, an open-sourced, real-time collaborative Python IDE designed specifically for students, education and pair programming purposes.

While tools like Replit and VS Code Live Share exist, they often come with significant bloat-paywalls, complex environments, and AI copilots that can actually hinder the learning process for beginners. As a second-year engineering student myself, I wanted to build the opposite: a lightweight, communication-first environment where the code is the focus.

The result is a fully free, browser-based IDE with real-time selections, voice/live chat, and shared drawing tools. It currently supports over 500 users.

Collab demo
Matplotlib Demo

Here is a deep dive into the architecture, the tech stack, and the specific engineering hurdles I faced building a "Google Docs for Python."

The Architecture

At a high level, the app needs to handle two distinct heavy-lifting tasks: synchronising state between multiple users in real-time, and executing Python code safely without crashing the browser.

The Stack:

  • Frontend: React, TailwindCSS, CodeMirror (Linting), Y.js (CRDTs).
  • Execution: Pyodide (WASM) running in Web Workers.
  • Backend: Django (Django Channels), PostgreSQL, Redis.
  • Infrastructure: Docker, Nginx, VPS.

Challenge 1: Running Python in the Browser (Safely)
The most significant technical challenge was execution. I didn't want to run user code on my backend (which introduces massive security risks and server costs). instead, I chose Pyodide, a port of CPython to WebAssembly (WASM). This allows the Python code to run entirely client-side.

However, a major hurdle appeared immediately: Blocking I/O.

Python’s input() function is blocking. If you run this on the main browser thread, the entire UI freezes while waiting for user input. This is a major deal-breaker for beginners who love using input(). To solve this, I had to run the Pyodide instance inside a Web Worker.

I utilized pyodide-worker-runner to manage the communication between the React frontend and the worker. This allows the main thread to remain responsive (handling UI updates and real-time syncing) while the worker handles synchronous Python execution, including support for running complex libraries like NumPy and Matplotlib (I had to edit some Matplotlib functions directly in a wrapper to output in the console properly). It also auto-installs any detected imported libraries.

Challenge 2: Real-Time Collaboration & State
For the "Google Docs" feel, I needed to handle race conditions. If User A types a character while User B deletes a line, how do we resolve the conflict?

I used Y.js, a library for Conflict-free Replicated Data Types (CRDTs). Y.js handles the complex merging logic, ensuring that all users eventually see the exact same document state regardless of network latency or packet order.

Challenge 3: The "Save" Problem (Redis + Celery)
Designing an efficient autosave system was the toughest backend challenge (excluding the Y logic).

  • Naive Approach: Save to PostgreSQL on every keystroke.
  • The Problem: This would hammer the database with thousands of write operations per minute for a single active group.

The Solution: A Redis Buffer. I implemented a "write-behind" caching strategy.

  1. Ingest: Real-time changes are pushed to a Redis layer (which also handles the Django Channels layers for WebSockets).
  2. Buffer: Active projects are tracked in memory.
  3. Persist: A Celery worker loops through active projects every minute to persist the changes from Redis to PostgreSQL.
  4. Cleanup: When all users leave a project, the state is flushed to the DB and cleared from the cache.

This turns thousands of potential DB writes into a single bulk update.

Deployment & Infrastructure

I decided to avoid managed services like Heroku or Vercel for the backend to keep costs low and learn the "ops" side of DevOps.

The entire backend is Dockerized and deployed on a roughly $7/mo VPS. This required manually configuring Nginx as a reverse proxy, setting up Certbot for SSL, and managing the Docker containers (I made 2 separate docker-compose files; one for development and one for production). I also set up a CI/CD pipeline using GitHub Actions to automate deployment.

It was a frustrating 8 hours of wrangling configurations, but it gave me total control over the environment.

What's Next?

The project is open source and open to contributors. I'm currently working on an offline "playground" feature (which won't require logging in), and also read-only and edit share links per project (currently, in order to collaborate, you must join a group via a keycode).

If you are a tutor, teacher, student, or just want to code with a friend, give it a try.

Live Site: pytogether.org
GitHub: github.com/SJRiz/pytogether

About Page

Top comments (0)