Creating my perfect journal app

September 25, 2026

Back in July 2023, a couple days before turning 18, I started playing with the idea of journaling. Not primarily for therapeutic purposes, but to have a log of every notable event that I went through. Before going to sleep, I'd jot down what I did that day, how I felt about it, and whatever I was thinking about in the moment.

Over time, this would allow me to build up a database of my whole adult life. I'd be able to figure out exactly on what day something happened, just by searching for some keywords, even if it was years ago. Additionally, I have a very bad memory and I'm often unable to recall how I felt about something after a couple months have passed. I could check whether I enjoyed doing something, and make more informed decisions based on that. But I wouldn't be able to achieve this with a paper-based diary, and I didn't trust any third-party service with my own private entries. And so, the concept of Journal was born.

Initial Version

I knew from the get-go I'd be writing it digitally. Some people prefer the feeling of handwriting their journal, but for me, the pros outweighed the cons. It's faster to write, I don't need to carry around another object with me wherever I go, I can write it in the dark and in bed, it's indexable and searchable, I can run analysis on it and draw statistics, I can read any entry without binary searching for it, nobody can read it when my devices are locked, and, provided I have backups, I can't lose it.

I threw the first version together in two days. The frontend was a Next.js app, and it was very bare-bones. The login page was a single button which opened a Google OAuth popup. The main page had a calendar showing which entries were filled in, a button to open today's entry, and a button to log out. The entry page itself was just a large <textarea> with a word counter and a save button. None of it was pretty, but it did the job for now.

A screenshot of the old Journal entry UI, as described above
I stared at this screen for 20 minutes a day, until I redesigned it in December 2024 to how it looks today

One thing was a clear priority since the very beginning though; the app needs to be able to handle multiple devices. If I really do intend to write an entry every single day, I need to be able to do it from my phone. It doesn't happen often that I'm without my laptop, but the app has to be ready for it. That said, this was during a time when I still had very little experience writing backend code. I didn't have a homelab setup, and I wasn't going to rent a server for this, so I went with Firebase. Every entry was stored in Firestore, in plain text on Google's servers, which was less than ideal for a journal app with tons of sensitive details I'd rather not have out there. Nevertheless, it was a start, and it could only get better from here.

A screenshot of the Firebase Firestore console, showing all the entries in plain text
Not exactly a privacy-first storage system

Iterating

Over time, I kept making improvements. This was an app I used every single day, and I'm a sucker for software which feels delightful to use. Investing time into Journal meant investing time into my journalling experience for the following years, if not decades.

The first of these major changes came in December 2023, when I finally moved away from Firebase and wrote my own backend using Cloudflare Workers and its sister service, D1. I'd gotten comfortable enough with Workers during the months prior, and it felt like the natural fit for Journal. I switched to my own account system instead of relying on Google OAuth. The entries were now being stored in a proper database, and I had server-side code to work with. The utility of this change is debatable, but I stopped using a proprietary storage engine and felt more in control of my own data. Everything was still unencrypted though, which meant I couldn't realistically release this project, not being able to guarantee data privacy.

A screenshot of the old calendar design — harsh straight white lines dividing the days with no corner radius
The old calendar design. December 26, 2023 was the last entry in Firebase.

In July 2024, summer break started again, which meant I had lots of time to pour into Journal. I finally added a search function — the main reason I started writing the journal in the first place. I added a "One Year Ago" button, so that every day, before writing an entry, I'd read what was going on in my life on that day last year. Most importantly though, I added an entry encryption system. The client would generate a secret encryption key, which would be stored only in your browser and never shared with the server. When saving an entry, the app would first encrypt it using that key and only send over the garbled data. When loading an entry, the server would send that garbled data back, and the app would decrypt it before showing it to the user. My server never sees the actual entry content. This meant I could start giving other people access to Journal, and guarantee that I wouldn't be able to read what they're writing. If an attacker gained access to my database, it would be practically useless to them. On the other hand, if your browser storage got wiped and you had no backup of your encryption key, you'd be out of luck. All of your entries were effectively gone forever.

Adding entry encryption gave me a lot of freedom in terms of writing down my deepest, darkest secrets. I added another layer of security: every time you opened the app, you would have to authenticate with a passkey. In practice, that meant scanning my fingerprint on my laptop, or going through Face ID on my phone. This was a purely client-side measure; nothing was preventing you from opening the browser devtools, marking yourself as authenticated, and accessing my entries. The point of this measure was to protect against a hypothetical case where I leave my computer unlocked and a family member, or someone else with physical access to my device, opens Journal out of curiosity.

At this point, the entries were still stored on and always loaded from the server. This meant that every time I wanted to search through the entries, the client would have to download and decrypt all of the entries from the server. More annoyingly though, it meant I couldn't write an entry when I had no service. I'd have to write it in my notes app, and then copy it over to Journal when I reconnected to the internet. Not an ideal workflow. In June 2025, I flipped it around. I looked into IndexedDB, but I found it complicated and confusing to work with, so I opted to use a wrapper library, Dexie. Journal would now load all the entries from its browser storage and serve the web assets from local cache, thus working fully offline. If you were connected to the internet, saving an entry would save it on the server too. If not, it would only save locally, and get updated on the server whenever the client would periodically sync.

I spent the rest of the 2025 summer break polishing Journal. Adding a proper versioning and updating system. Building a proper settings interface. Making the calendar swipeable on mobile (this took enough time that i spun it off into a separate demo). I migrated Journal away from Next.js, over to TanStack Router and Vite. The TanStack router homepage currently looks extremely vibe-coded, but the framework is great. Next.js was notoriously hard to host outside of Vercel, and I wasn't a fan of neither the company, nor the framework's close ties to their commercial offerings. I unified the frontend and backend into a monorepo and spent time making the development experience nicer.

A screenshot of the Wakatime dashboard showing the time spent on each project in 2025
I spent more than 100 hours working on Journal in 2025 alone, the most out of any project that year.

This summer, I finally decided to release Journal as a public project in my portfolio. It seemed like a relatively easy task, but over the years I'd been making design decisions which always assumed the user knows what they're doing. For example, the encryption system was exceptionally fragile. It relied on the user generating an encryption key on one device and importing it on every other device. If you generated another encryption key on any device linked to Journal, you'd face encryption/decryption issues constantly and untangling them was a nightmare. To that end, I recently added checks to prevent double-key issues and added a convenient way to transfer your encryption key to other devices via a QR code. I also added warnings to hopefully motivate users to download their encryption keys, since they truly are unrecoverable.

I'm quite proud of the QR Code key sharing protocol. Despite the warnings, I believe the QR code is actually safe to share. Read the docs for more info.

Reflection

And that brings us to today. Having poured around 220 hours into the development of Journal over more than 3 years, more than any other personal project I've ever worked on (maybe except Placeholder? I didn't have any time tracking back then). The app has served me well enough to contain nearly half a million words of my thoughts and an estimated 400 hours of writing time.

It really is my perfect journal app. It doesn't have the ability to attach images to entries, or any other fancy features; it has just enough features that I want, and nothing more. It runs on any device, works offline, syncs, has great privacy and is very dear to me. The app, its scope, and its tech stack, have grown and changed alongside me.

Of course, I'm not done with it just yet. I have plenty of ideas for what else to add. Better searching options, the ability to switch out your encryption key, a more efficient sync protocol, the list goes on. And as long as I keep opening it every single night, I'll never be fully satisfied. But it is a big step for me to finally be able to open it up to the world.

I've dabbled with AI-assisted development before. Projects like SLATE would likely not have been possible in a reasonable timeframe (that is, the time I'm willing to spend on that particular project) without it. More recently, I've been practicing agentic engineering, a.k.a. vibe-coding, for work. But I find Journal special. I feel a great sense of ownership over the whole project — both the code and the entries themselves — and fear that introducing an LLM into Journal's development workflow would take that away from me.

This is my Journal. And after all this time and effort, I'm giving it to you. Use it, or don't; give it a shot, try it out. I've found a lot of peace in documenting my whole life. Maybe you will too.

https://journal.simondmc.com

← Back to posts