In this post, I’ll walk you through how I built a Go Playground REPL clone from scratch — powered by a Go backend that compiles user-submitted code securely in Docker, deployed with GitHub Actions to AWS Elastic Beanstalk, and paired with a beautiful frontend using Vue.js, Pinia, Tailwind CSS, and Monaco Editor.
Tech Stack
- Backend: Go (Golang), Docker, Gin, os/exec
- Frontend: Vue 3, Pinia, Tailwind CSS, Monaco Editor
- DevOps: GitHub Actions, DockerHub, AWS Elastic Beanstalk
What I Built
- An interactive code editor for writing and executing Go programs.
- A secure backend that:
- Runs code inside a Docker container
- Enforces timeouts to prevent infinite loops
- Handles malicious input gracefully
- A responsive frontend with live theme switching, program examples, and output panels.
Backend Setup
I used the os/exec package in Go to compile and run user code inside a Docker container, isolated from the host.
Sample Go run handler:
func RunCode(c *gin.Context) { var payload struct { Code string `json:"code"` } if err := c.ShouldBindJSON(&payload); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request format"}) return } output, err := runInDocker(payload.Code) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"output": output, "error": ""}) }
Sample Dockerfile:
FROM golang:1.24-alpine WORKDIR /app COPY . . RUN go build -o repl-server ./cmd CMD [ "./repl-server" ]
GitHub Actions Deployment
I set up GitHub Actions to automatically build our Docker image, push to ECR, and deploy to AWS Elastic Beanstalk.
Key CI/CD steps:
- name: Build Docker Image run: docker build -t repl-api . - name: Push to ECR run: | aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin ${{ secrets.ECR_URL }} docker tag repl-api:latest ${{ secrets.ECR_URL }}/repl-api:latest docker push ${{ secrets.ECR_URL }}/repl-api:latest - name: Deploy to EBS run: | eb init -p docker go-repl --region us-west-2 eb deploy
Frontend Setup
Used Vue 3 with Pinia to manage state and Monaco Editor for code editing.
Vue + Monaco Editor integration (sample):
<template> <MonacoEditor v-model="code" :theme="isDark ? 'vs-dark' : 'vs-light'" language="go" /> </template> <script setup> import MonacoEditor from '@monaco-editor/vue' const code = ref(`package main\n\nimport "fmt"\n\nfunc main() {\n fmt.Println("Hello, world!")\n}`) </script>
Sample UI with Tailwind CSS:
<div class="max-w-4xl mx-auto px-4 py-10"> <h1 class="text-3xl font-bold">Go Playground REPL</h1> <div class="h-96 mt-4 border rounded bg-white"> <CodeEditor v-model="code" /> </div> </div>
Program Examples Dropdown
Added dropdown support with built-in Go examples like
- Fibonacci
- Peano Integers
- Prime Checker
- Bubble Sort
- Pi Calculation
Securing Execution
Used these techniques to sandbox the code:
- Timeout using context.WithTimeout
- Docker resource constraints (--memory, --cpus)
- Output/error size limits
- Validated JSON input structure
Future Improvements
This setup is built with extensibility in mind.
- Add support for JavaScript, Java, Python, etc.
- Enable stdin support in Docker for user input
- Add user accounts and save session history
- Use WebSocket for real-time compile streams
🌐 Live Demo
📝 Final Thoughts
This project was a fun blend of backend performance, frontend UX, and DevOps automation. It’s a perfect playground for experimenting with Go and building a polished, full-stack developer tool.
Feel free to fork and extend it further. Hope this helps you in your learning journey!
Repo
Github Repo
Top comments (0)