Skip to content

Getting Started

Deploy NextJudge and verify it works end to end.

  • Docker + Docker Compose
  • 4 GB RAM minimum (8 GB if running web + judge together)
  • Ports free: 5000 (API), 5432 (Postgres), 5672 (RabbitMQ), 8080 (web)

Clone the repo. Everything below runs from the root.

Backend only:

Terminal window
./deploy.sh

Backend + web UI:

Terminal window
./deploy.sh web

First run builds the judge base image. Grab coffee. Subsequent starts are faster.

Terminal window
curl -i http://localhost:5000/healthy

You want:

HTTP/1.1 200 OK

Anything else (connection refused, 502, hang) means the data layer isn’t up yet. docker ps should show Postgres, RabbitMQ, data layer, and judge containers. Names vary; healthy counts more than spelling.

Web UI: http://localhost:8080. The first compile in dev mode can take a minute.


This is the walkthrough. Deploy with ./deploy.sh web, then follow along.

Open http://localhost:8080, sign up with email/password or GitHub (if configured in .env.dev).

Want admin powers? Set your email in ADMIN_EMAILS before starting, then register with that email. Details in Authentication.

Skip the UI. Get a token directly:

Terminal window
curl -s -X POST http://localhost:5000/v1/basic_register \
-H "Content-Type: application/json" \
-d '{"name":"ada","email":"ada@example.com","password":"example-password"}' \
| jq .

Copy token and id from the response. We’ll call them $TOKEN and $USER_ID.

Terminal window
curl -s http://localhost:5000/v1/languages | jq '.[0:3]'

Pick a language id for Python (or whatever you like). Note it as $LANG_ID.

No auth required. If this returns [], your database didn’t seed. ./dev-deploy.sh sets SEED_DATA=true; plain ./deploy.sh may not. You can still register languages as admin later.

With $TOKEN set (raw JWT, no Bearer):

Terminal window
curl -s http://localhost:5000/v1/problems \
-H "Authorization: $TOKEN" | jq '.[0] | {id, title, difficulty}'

No problems? Dev seed may not have run, or you’re on a fresh prod deploy. Create one in the admin UI, or ask an admin to POST /v1/problems. Note id as $PROBLEM_ID.

Terminal window
curl -s -X POST http://localhost:5000/v1/submissions \
-H "Authorization: $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"user_id\": \"$USER_ID\",
\"problem_id\": $PROBLEM_ID,
\"language_id\": \"$LANG_ID\",
\"source_code\": \"print('hello')\"
}" | jq '{id, status}'

Expect "status": "PENDING". Save id as $SUB_ID. The judge picks it up from RabbitMQ.

Terminal window
curl -s http://localhost:5000/v1/submissions/$SUB_ID \
-H "Authorization: $TOKEN" | jq '{status, time_elapsed, stderr}'

Run it a few times. PENDING for a few seconds is normal. PENDING for minutes is not (see Judge stuck below).

Success looks like "status": "ACCEPTED" (if your code actually solved the problem) or "WRONG_ANSWER" / "COMPILE_TIME_ERROR" (if it didn’t). All three mean the pipeline works. CE on print('hello') for a hard problem is expected. The point is the judge ran.

Checkpoint: you deployed, authenticated, submitted, and got a non-PENDING status. You’re done. Everything else in these docs is refinement.


Hot reload, source mounted, seed data:

Terminal window
./dev-deploy.sh web

Other flags: nojudge (skip judge), noelastic (skip Elasticsearch profile). Full dev workflow: Development guide.

Nuclear option. Wipes all data.

Terminal window
./fully-reset.sh && ./deploy.sh web

Infrastructure in Docker, one process on the host:

ServiceCommand
Data layercd src/data-layer && go run src/main.go -d -p 5000
Webcd src/web && npm run dev
Judgecd src/judge && python src/app.py

Postgres + RabbitMQ must already be running.

NextJudge expects 5000, 8080, 5432, and 5672 free. Something else bound to those ports blocks startup.

Terminal window
lsof -i :5000 :8080 :5432 :5672

Stop the conflicting process or change the mapped ports in the compose file.

The data layer expects Postgres on the host/port from your compose env (default 5432). A Postgres instance already running on the host often wins that port.

Terminal window
docker logs $(docker ps -qf name=postgres)

Confirm the Postgres container is healthy and that DB_HOST / DB_PASSWORD match compose.

Submission stays PENDING and the RabbitMQ queue grows when workers are down or can’t authenticate back to the API.

Checklist:

  1. Judge container running? docker ps | grep judge
  2. Judge logs: docker logs $(docker ps -qf name=judge) 2>&1 | tail -20
  3. JUDGE_PASSWORD identical on data layer and judge
  4. RabbitMQ credentials match on both sides

A healthy judge log shows receive → compile → PATCH result. No log activity usually means nothing is consuming the queue.

The initial judge base image build is heavy. Give Docker at least 4 GB RAM (8 GB if you run web + judge together).