Share your photos, videos & files securely with one simple link.
- Any file, any size — Upload photos, videos, PDFs and more. No accounts required for the people you share with.
- One link — Upload once, get a single shareable link instantly.
- Password protection — Gate your link behind a password so only the people you choose can open it.
- Links that expire — Every share link self-destructs after 24 hours. No cleanup, no clutter.
- Auth built in — Email/password and Google OAuth via Better Auth.
- Direct-to-cloud uploads — Files stream straight to Cloudinary with signed uploads; they never touch our server.
- Open source — Free to use, free to self-host. Your files, your server, your rules.
Drop screenshots of the landing page and dashboard here, e.g.
| Landing page | Dashboard | |:---:|:---:| |  |  |
High-level flow of the app — auth, uploads and storage:
flowchart TB
subgraph Client["Browser (Client)"]
UI["Next.js UI<br/>/ /login /dashboard"]
end
subgraph Server["OpenShare Server (Next.js)"]
NEXT["Next.js App Router"]
API["POST /api/upload<br/>(auth-gated)"]
AUTH["Better Auth<br/>email/password + Google OAuth"]
end
subgraph Data["Data Layer"]
PRISMA["Prisma ORM"]
PG[("PostgreSQL (Neon)<br/>users · sessions · files")]
end
CLOUD[("Cloudinary<br/>file storage")]
UI --> NEXT
NEXT --> AUTH
AUTH --> PRISMA --> PG
UI --> API
API --> CLOUD
UI -- "signed upload (direct)" --> CLOUD
CLOUD -- "secure_url" --> UI
An editable Excalidraw version of this diagram is available at
docs/architecture.excalidraw — open it at
excalidraw.com (drag & drop the file) to tweak it or export a PNG.
- The user uploads files in the dashboard.
- The client calls
POST /api/uploadwhich checks the session and returns a Cloudinary upload signature (never exposes the API secret to the browser). - The client uploads the files directly to Cloudinary with that signature.
- Cloudinary returns a
secure_urlfor each file. - File metadata —
shareToken, optionalpasswordHashandexpiresAt— is stored in PostgreSQL via Prisma.
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) + React 19 |
| Language | TypeScript |
| Styling | Tailwind CSS v4 + shadcn/ui |
| Auth | Better Auth (email/password + Google OAuth) |
| Database | PostgreSQL via Neon |
| ORM | Prisma with driver adapter |
| File storage | Cloudinary signed uploads |
| Package manager | Bun |
- Bun (or Node.js 20+)
- A PostgreSQL database (e.g. free tier on Neon)
- A Cloudinary account
- (Optional) a Google OAuth app
git clone https://github.com/your-username/openshare.git
cd openshare
bun installCopy the following into a .env file at the project root:
# Auth (generate a strong secret with: openssl rand -base64 32)
BETTER_AUTH_SECRET=your-secret-here
BETTER_AUTH_URL=http://localhost:3000
# PostgreSQL
DATABASE_URL="postgresql://user:password@host:port/dbname?sslmode=require"
# Google OAuth (optional — remove socialProviders if unused)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
# Cloudinary
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secretbunx prisma generate
bunx prisma db pushbun run devOpen http://localhost:3000 🎉
| Command | Description |
|---|---|
bun run dev |
Start the dev server |
bun run build |
Generate Prisma client + production build |
bun run start |
Start the production server |
bun run lint |
Run ESLint |
bunx prisma studio |
Browse the database |
openshare/
├── app/
│ ├── api/
│ │ ├── auth/[...all]/route.ts # Better Auth handler
│ │ └── upload/route.ts # Signed upload signature endpoint
│ ├── dashboard/page.tsx # Dashboard (client shell)
│ ├── login/page.tsx # Login / register
│ ├── page.tsx # Landing page
│ ├── layout.tsx
│ └── globals.css
├── components/
│ ├── ui/ # shadcn/ui primitives
│ ├── hero.tsx # Landing hero
│ ├── features.tsx # Landing feature section
│ ├── footer.tsx # Landing footer
│ ├── navbar.tsx
│ ├── DashboardShell.tsx # Upload + share link UI
│ └── LoginPage.tsx
├── lib/
│ ├── auth.ts # Better Auth server config
│ ├── auth-client.ts # Better Auth client
│ ├── cloudinary.ts # Cloudinary config
│ └── upload.ts # Signed upload helper
├── prisma/
│ ├── schema.prisma # User, Session, File models
│ └── migrations/
├── docs/
│ └── architecture.excalidraw # Editable architecture diagram
└── public/
- Public share page to view/download shared files
- Upload history + revoke links
- Custom link expiry duration
- Email notifications
- Rate limiting & abuse protection
Pull requests are welcome! Open an issue or submit a PR. For major changes, please open an issue first to discuss what you'd like to change.
Made with ❤️ by OpenShare contributors