
How to Make an App Like Ulysses

How to Make an App Like Ulysses
Ulysses has earned a near-cult following among writers, journalists, bloggers, and academics. It isn't the flashiest app on the App Store, and that's precisely the point. It offers a calm, distraction-free writing environment backed by a serious organizational system, seamless sync across Mac, iPad, and iPhone, and publishing pipelines that let you push straight to WordPress, Ghost, or Medium.
If you're planning to build a writing app in the same class, you're not just building a text editor. You're building a trustworthy home for someone's life's work. That raises the bar on sync reliability, data integrity, and interface restraint far above a typical productivity app.
Here's a practical breakdown of what it takes.
Understand What Actually Makes Ulysses Work
Before writing a line of code, it's worth separating the surface features from the underlying philosophy.
The surface features:
- A markdown-based editor with inline formatting
- A three-pane library: groups, sheet list, editor
- Sheets instead of files, which can be merged, split, and reordered
- Keywords, filters, and smart folders for organization
- Goals and writing statistics
- Export to PDF, DOCX, EPUB, HTML
- Direct publishing to blogging platforms
- iCloud sync across all Apple devices
The philosophy underneath:
- The writer should never be interrupted by the interface
- Structure should emerge from writing, not be imposed before it
- Content and presentation are separate concerns
- Nothing should ever be lost
That last point matters more than anything else on the list. Writers forgive missing features. They do not forgive a lost draft. Your architecture decisions should flow from that priority.
Define Your Core Feature Set
Trying to match Ulysses feature-for-feature in version one is a trap. Ulysses has been in active development for well over a decade. Instead, scope an MVP that delivers a complete, coherent experience in a narrower lane.
Must-have for v1
The editor. A markdown or markdown-flavoured editor with syntax highlighting, inline formatting shortcuts, and keyboard-first navigation. This is 80% of the perceived quality of your app. Invest accordingly.
The sheet model. Instead of documents in folders, Ulysses uses "sheets" — atomic chunks of writing that can be combined at export time. This is the single most differentiating structural idea. A chapter can be five sheets. A blog post can be one. Merging and splitting should be one keystroke.
A library with real organization. Nested groups, drag-and-drop reordering, and a search that's instant even across thousands of sheets.
Rock-solid sync. Non-negotiable. More on this below.
Export. At minimum: plain text, markdown, PDF, and DOCX. Writers need to hand work to editors who use Word.
Distraction-free mode. Full screen, typewriter scrolling, adjustable line width, dark and light themes.
Fast-follow features
- Keywords and tag-based filtering
- Saved filters / smart folders
- Word count goals with per-sheet and per-group targets
- Writing statistics and session tracking
- Attachments, notes, and images per sheet
- Revision history
- Direct publishing to WordPress, Ghost, Medium
- Custom export styles and themes
- Split view and dual-pane editing
Things you can safely skip early
Deep scriptability, custom stylesheet languages, external folder support, and elaborate theme marketplaces. These are power-user rewards that only make sense once you have power users.
Choose Your Platform Strategy
Ulysses is Apple-only, and that focus is a feature rather than a limitation. It lets the team use native frameworks, ship a genuinely Mac-like Mac app, and integrate deeply with iCloud, Shortcuts, and system-level text handling.
You have three broad options.
Native Apple-first
Swift and SwiftUI with AppKit or UIKit where you need fine control. This gives you the best text rendering, the best keyboard handling, and the tightest system integration. TextKit 2 gives you a mature foundation for a custom editor. If your target audience is writers on Mac and iPad, this is the strongest choice.
The trade-off is that you're building a second codebase later if you ever want Windows or Android.
Cross-platform with native editor cores
Flutter or React Native for shell, navigation, and library UI, with a platform-specific text editing layer. This is harder than it sounds. Text editing is the one area where cross-platform frameworks consistently disappoint — cursor behaviour, IME support for non-Latin languages, text selection gestures, and undo stack fidelity all tend to feel subtly wrong.
If you go this route, budget real engineering time for the editor specifically.
Web-first with desktop wrappers
Electron or Tauri plus a web app, using a mature editor framework like ProseMirror, CodeMirror 6, or Lexical. This gets you Mac, Windows, Linux, and browser coverage from one codebase, and these editor libraries are genuinely excellent. iOS and Android become the harder problem, and battery and memory usage on desktop need careful attention.
Tauri is worth a serious look over Electron if bundle size and memory matter to you.
Practical recommendation: if you're a small team targeting serious writers, go native Apple-first and do it exceptionally well. A narrow, excellent app beats a broad, mediocre one in this category every time.
Architect the Data Layer Carefully
This is where writing apps live or die.
Model sheets as the atomic unit
Each sheet needs:
- A unique, stable identifier
- Body content
- Ordering metadata within its parent group
- Keywords, notes, attachments
- Created and modified timestamps
- A revision chain
Store content in a structured, portable format. Plain markdown with a metadata sidecar is the most future-proof option. Proprietary binary formats create lock-in that writers rightly distrust, and they make debugging sync issues miserable.
Pick a local database with intent
On Apple platforms, Core Data with CloudKit or SwiftData gives you a lot of sync plumbing for free. SQLite via GRDB gives you more control and better performance on large libraries. Realm is another solid option with built-in sync.
Whatever you choose, make sure it handles:
- Thousands of sheets with instant search
- Full-text indexing
- Atomic writes so a crash mid-save never corrupts a sheet
- Efficient partial loading — don't hold the entire library in memory
Design sync as a first-class system
Naive sync is the most common failure in this app category. A writer edits on iPad in airplane mode, edits the same sheet on Mac, then both come online. What happens?
Your options:
CloudKit with Core Data / SwiftData. Lowest effort on Apple platforms, free at reasonable scale, and users trust iCloud. Conflict resolution is coarse, so you'll need custom merge logic for sheet bodies.
CRDTs. Conflict-free replicated data types like Yjs or Automerge let concurrent edits merge deterministically without a server arbitrating. This is the gold standard for text sync and what modern collaborative editors use. The learning curve is real but the payoff is enormous.
Operational transforms with a central server. More traditional, requires you to run infrastructure, and gives you the option of real-time collaboration later.
File-based sync via iCloud Drive or Dropbox. Simple and transparent, and users can see their files. Prone to conflict files and partial writes.
For a Ulysses-class app, a CRDT-backed sheet body with metadata synced through a conventional store is a strong architecture. Whatever you build, never resolve conflicts by silently discarding one version. Keep both, surface them, and let the writer decide.
Version history is a safety net, not a luxury
Snapshot sheets on a schedule and on significant change. Store diffs rather than full copies to keep storage reasonable. Let users browse and restore any prior version. This single feature buys more user trust than almost anything else you can ship.
Build the Editor Right
The editor is your product. Everything else is supporting cast.
Markdown handling
Ulysses uses a "Markdown XL" flavour — standard markdown plus extensions for annotations, footnotes, and inline comments. Decide early whether you're implementing strict CommonMark, a superset, or a rich-text model that exports to markdown.
Implement inline visual formatting where bold text appears bold while the syntax markers remain visible but de-emphasized. Writers find this more comfortable than either raw syntax or a fully hidden WYSIWYG view.
Performance targets
- Typing latency under 16ms, always
- No stutter in documents of 50,000+ words
- Instant scroll in long sheets
- Search results as you type
Use incremental parsing. Re-tokenizing an entire document on every keystroke will fail at scale. Tree-sitter or a hand-rolled incremental markdown parser both work well.
Details that signal quality
- Typewriter scrolling that keeps the cursor vertically centered
- Smart quotes, dashes, and ellipses with per-language rules
- A proper undo stack that groups by typing burst, not by character
- Full keyboard shortcut coverage and customization
- Robust IME support for CJK input
- Correct handling of emoji, RTL text, and combining characters
- Accessibility: VoiceOver, Dynamic Type, reduced motion
These are invisible when done right and glaring when done wrong.
Design the Interface Around Restraint
The Ulysses aesthetic is about removing decisions from the writer's path.
Three-pane layout. Library, sheet list, editor. Collapsible so the writer can go from full context to pure text in one keystroke.
Typography as a feature. Ship a small set of excellent, well-paired fonts. Expose line height, line width, paragraph spacing, and font size. Writers are opinionated about this and will happily spend twenty minutes tuning it.
Themes. Light, dark, and sepia at minimum, with a proper theme editor as a fast-follow. Respect system appearance by default.
Progressive disclosure. Keywords, goals, statistics, attachments, and notes all live in panels that stay closed until summoned.
No modal interruptions. No onboarding carousels blocking the first launch, no upgrade prompts mid-sentence, no notification badges on a writing surface.
Handle Export and Publishing
Export is where a writing app proves it respects the writer's downstream workflow.
Core formats: plain text, markdown, HTML, PDF, DOCX, EPUB. PDF and DOCX generation are more involved than they look — plan for a proper templating layer rather than string concatenation.
Style separation. Content stays clean; export styles determine typography, margins, headers, and page numbering. Let users create and share styles.
Compilation. Exporting a group should stitch its sheets together in order, with configurable separators. This is what makes the sheet model pay off for long-form work.
Publishing integrations. WordPress via the REST API, Ghost via its Admin API, Medium via its API, and Micro.blog. Support drafts, tags, featured images, and scheduled posts. OAuth where available, app passwords where not.
Pick a Business Model That Fits
Ulysses moved from paid-upfront to subscription in 2017 and took public heat for it, but the model has sustained continuous development since. Writing apps have real ongoing costs — sync infrastructure, OS updates, publishing API maintenance — so recurring revenue makes sense.
Realistic options:
- Subscription with monthly and annual tiers, plus education pricing. Offer a genuinely useful free trial, not a crippled one.
- Paid upfront with paid major upgrades. Users like it; it's hard to sustain.
- Freemium with a sheet limit or export restriction on the free tier. Be careful: a free tier that feels punitive damages goodwill in a community that talks to each other constantly.
Whatever you choose, be transparent about it before install. The writing community is small, vocal, and has a long memory.
Plan a Realistic Build
A rough sequence for a small team:
Phase 1 — Foundation. Data model, local persistence, basic editor, library navigation. Single platform.
Phase 2 — Editor depth. Markdown parsing and highlighting, inline formatting, keyboard shortcuts, typewriter mode, themes, performance tuning.
Phase 3 — Sync. Cloud architecture, conflict resolution, revision history, offline-first behaviour. Test aggressively with real multi-device scenarios and forced network failures.
Phase 4 — Export and publishing. Format generation, style templates, platform integrations.
Phase 5 — Second platform. Companion mobile or desktop app sharing the sync layer.
Phase 6 — Power features. Keywords, filters, goals, statistics, attachments, split view.
Expect twelve to eighteen months to a credible v1 with a small senior team, and plan for continuous refinement after that. This is not a category where you ship once and move on.
Common Mistakes to Avoid
Underestimating the editor. Teams routinely allocate two weeks to "the text editing part" and spend four months. Front-load it.
Shipping sync you haven't stress-tested. Test with airplane mode, mid-sync force quits, clock skew, and simultaneous edits on three devices. Every unhandled case becomes a support ticket about lost work.
Feature creep before polish. Ten features that feel great beat forty that feel rough.
Proprietary lock-in. Offer full, clean export from day one. Writers choose tools they can leave.
Ignoring the community. Writers discuss tools obsessively on forums, newsletters, and social media. A responsive, honest team presence is genuinely effective marketing in this niche.
Final Thoughts
Building an app like Ulysses is a craft exercise disguised as a software project. The technical challenges — incremental parsing, conflict-free sync, high-fidelity export — are substantial but well understood. The harder work is judgment: knowing what to leave out, where to spend interface budget, and how to make an app feel calm.
Start with the editor. Make typing in your app feel better than typing anywhere else. Build sync you'd trust with your own unpublished manuscript. Then add structure, organization, and publishing around that core.
Get those foundations right and you'll have something writers don't just use, but recommend.
Have a project in mind? Contact Sodio Technologies to discuss your requirements and explore the right technology solution for your business.
/// Work with us
Talk to the engineers who'd build it
You'll get a technical scope, timeline and cost estimate from the people doing the work, not an account manager. In-house team, no subcontracting, since 2016.
