A minimalist, self-hosted bookmarking tool inspired by the golden era of del.icio.us.
Built with React 19, Vite, and Supabase. Designed for speed, privacy, and simplicity.
- Private by Design: You own the data. It lives in your own Supabase project.
- Retro Interface: A clean, no-nonsense UI inspired by early 2000s social web.
- Powerful Organization: Support for both Tags and Folders.
- Read Later: Mark items as unread to catch up on them later.
- Personal Notes: Add markdown notes to any bookmark.
- Full Search: Instantly filter by tag, URL, title, or description.
- Import/Export: Full data ownership with SQL, CSV, and XML export options.
- Node.js (v18 or higher)
- A free Supabase account.
Since this is a serverless app, you need to set up your database first.
- Create a new project at database.new.
- Navigate to the SQL Editor in the sidebar.
- Paste and run the following script to create the database schema and security policies:
-- 1. Create the Bookmarks Table
create table bookmarks (
id bigint generated by default as identity primary key,
created_at timestamp with time zone default timezone('utc'::text, now()) not null,
url text not null,
title text not null,
description text,
tags text[] default '{}',
folders text[] default '{}',
notes text,
to_read boolean default false,
user_id uuid references auth.users not null default auth.uid()
);
-- 2. Enable Row Level Security (RLS)
-- This ensures data is completely private to the logged-in user.
alter table bookmarks enable row level security;
create policy "Users can only see their own bookmarks" on bookmarks for select using (auth.uid() = user_id);
create policy "Users can insert their own bookmarks" on bookmarks for insert with check (auth.uid() = user_id);
create policy "Users can update their own bookmarks" on bookmarks for update using (auth.uid() = user_id);
create policy "Users can delete their own bookmarks" on bookmarks for delete using (auth.uid() = user_id);
-- 3. Setup Storage for Avatars
insert into storage.buckets (id, name, public) values ('avatars', 'avatars', true);
create policy "Avatar images are publicly accessible" on storage.objects for select using ( bucket_id = 'avatars' );
create policy "Anyone can upload an avatar" on storage.objects for insert with check ( bucket_id = 'avatars' AND auth.role() = 'authenticated' );- Go to Project Settings -> API.
- Copy the Project URL and the
anonpublic key.
-
Clone the repository:
git clone https://github.com/yourusername/linkkiste.git cd linkkiste -
Install dependencies:
npm install
-
Configure environment variables: Create a file named
.envin the root directory:VITE_SUPABASE_URL=https://your-project-ref.supabase.co VITE_SUPABASE_ANON_KEY=your-long-anon-key-string
-
Start the app:
npm run dev
You can deploy this for free on Vercel, Netlify, or Cloudflare Pages.
- Push your code to GitHub.
- Import the project into Vercel.
- In the "Environment Variables" section, add:
VITE_SUPABASE_URLVITE_SUPABASE_ANON_KEY
- Deploy!
⚠️ Important: If the first deployment fails because you forgot the variables, simply adding them isn't enough. You must go to the Deployments tab, click the three dots on the failed deployment, and select Redeploy.
- Log in to Cloudflare and go to Compute (Workers & Pages) -> Pages.
- Click Connect to Git and select your repository.
- Build Settings:
- Framework Preset: Vite
- Build Command:
npm run build - Output Directory:
dist
- Environment Variables: Add your
VITE_SUPABASE_URLandVITE_SUPABASE_ANON_KEYhere.
⚠️ Critical: Vite "bakes" environment variables into the code at build time. If you add the variables after the initial build runs (or if the first build fails), you must go to Deployments -> Retry deployment to rebuild the app with the keys included.
Okay, here is the honest truth: Since this is a self-hosted private tool, there is no magic "Install" button in the App Store that automatically sets up sharing. You have to wire it up yourself.
This project includes a local browser extension (in the public/extension folder) that lets you save links with one click.
- Go to
chrome://extensions. - Enable Developer Mode (toggle in top right).
- Click Load Unpacked.
- Select the
public/extensionfolder inside this project directory. - Click the new icon in your toolbar and enter your App URL (e.g.,
https://my-linkkiste.vercel.app).
There is currently no native "Share to LinkKiste" system menu integration out of the box (requires complex PWA manifest configuration).
- Open your deployed app in your mobile browser.
- Add to Home Screen to install it as a PWA.
- To save a link, copy the URL, open LinkKiste, and tap + Add.
This tool is designed to be single-user (or limited user).
- Register your account immediately after deployment.
- Go to your Supabase Dashboard -> Authentication -> Providers -> Email.
- Disable "Confirm email" (unless you want to set up SMTP).
- CRITICAL: Once you have created your account, go to Authentication -> Settings -> User Signups and disable "Allow new users to sign up".
- This prevents random strangers from using your instance as their database.
Feel free to open issues or submit PRs. This is a passion project to keep the spirit of the old web alive.
MIT
