David Fregoli
Projects Blog

Building a self-hosted Nextcloud replacement in Go and React

March 12, 2026 · 2 min read

I've been running Nextcloud for years. It does everything — file sync, calendars, contacts, notes, tasks, video calls. The problem is it also breaks everything. PHP memory limits, background job failures, upgrade paths that require reading changelogs like legal documents. I just want file storage.

So I'm building LessCloud: a self-hosted cloud storage server with a clean UI, minimal infrastructure, and Nextcloud API compatibility so existing mobile apps keep working.

Why not just use Nextcloud

Nextcloud requires PHP, Redis, a cron job, and careful tuning to avoid the dreaded "background jobs not running" warning. Every major upgrade is a coin flip. And most of the features — Talk, Calendar, Deck, Mail — are bolted-on apps that add complexity without adding reliability.

I only use about 10% of Nextcloud: file storage, sync, and sharing. LessCloud does exactly that, with a single Go binary and Postgres.

The stack

Layer Technology
Backend Go, Chi router, sqlc
Database PostgreSQL
Frontend React, Vite, TanStack Router, TanStack Query
Styling Tailwind CSS

No Redis. No queue system. No object storage adapter. Files go on disk, metadata goes in Postgres, and the Go binary serves both the API and the frontend.

Nextcloud compatibility layer

The key feature: existing Nextcloud mobile apps work out of the box. LessCloud implements:

  • WebDAV — full file operations at /remote.php/dav/files/{username}/
  • Chunked uploads — for large files via /remote.php/dav/uploads/{username}/
  • OCS API — capabilities, user info, sharing
  • Login flow v2 — the browser-based auth flow that Nextcloud apps use to get app passwords

This means you can point the Nextcloud Android/iOS app at your LessCloud instance and it just works. No custom app needed.

What it actually does

The web UI is closer to Google Drive than Nextcloud: list and grid views, drag-and-drop uploads, right-click context menus, keyboard shortcuts, and a details panel. Everything you'd expect.

Under the hood:

  • Full-text search powered by Postgres tsvector/tsquery — no Elasticsearch needed
  • File versioning with configurable retention
  • Public sharing with optional passwords and expiration
  • Realtime updates via Server-Sent Events — open two tabs and changes appear instantly

Deployment

Same philosophy as my other projects: single docker compose up -d. The multi-stage Dockerfile builds the React frontend, compiles the Go binary, and produces a minimal Alpine image. Two containers total — the app and Postgres.

Configuration is entirely through environment variables. No config files, no admin panels with 200 settings.

Current state

It's usable for daily driving. I've migrated my own files off Nextcloud and haven't looked back. The Nextcloud Android app syncs photos and documents without issues. The main things still missing are calendar/contacts (CalDAV/CardDAV) — but honestly, I'm not sure I want to add them. The whole point is to do less.