Most developers have the same problem with learning: the list keeps growing and the progress doesn't.
You bookmark a course. You buy a book. You save an article to read later. Three months pass and none of it has moved. The problem isn't motivation — it's that there's no system connecting what you want to learn to where you actually are with each resource.
A Notion learning resource tracker fixes this. Not by adding more friction, but by giving you a single place where everything you're learning lives — with progress calculated automatically, filtered views that surface what's active versus what's stalled, and a lesson-level relation that tracks exactly how far into each resource you've gone.
This guide builds the exact system used in DevHub's Learning Resources database, based on real structure you can replicate today.
What You're Building
A Learning Resources database in Notion with:
- Four resource types tracked in one place — courses, books, articles, tutorials
- Automatic progress calculation based on completed lessons versus total length
- A completion checkbox that updates itself when status changes
- Five filtered views covering every angle you need — active learning, pipeline by type, topic-specific filters, and reading backlog
- A relation to a Lessons database so progress reflects real unit-level completion, not gut estimates
Who This Is For
Developers, engineers, and self-taught learners who:
- Buy courses and never finish them
- Have a reading list that grows faster than it shrinks
- Want learning tracked alongside their actual work rather than in a separate app
- Need to see what's active right now versus what's queued versus what's done
Step 1: Create the Learning Resources Database
Create a new full-page database in Notion. Name it Learning Resources.
This database is the core. Everything else — the lessons, the views, the formulas — connects back to it.
Step 2: Set Up the Core Properties
Delete Notion's default properties and add the following exactly as listed.
Name (Title)
Keep the default Title property. Rename it to Name if it isn't already.
Write resource names specifically enough to be useful when scanning a list. "JavaScript Course" is not useful. "The Odin Project — Full Stack JavaScript" is.
Link (URL)
Add a URL property named Link.
Paste the direct URL to the course, article, book page, or documentation. This makes every resource one click away from the database — no hunting through bookmarks.
Type (Select)
Add a Select property named Type.
Options:
ArticleBookCourseTutorial
Type determines how you filter and group your resources. The Learning Pipeline view groups by Type so you can see at a glance whether your active learning is balanced across formats or concentrated in one area.
Status (Select)
Add a Select property named Status.
Options:
To ReadIn ProgressCompleted
Keep exactly these three options and these exact names — the formulas reference them directly. If you rename them, the Is Done? formula and the filtered views will break.
Status is the primary property you update as you move through a resource. Everything else — progress, filtering, board placement — flows from this field.
Tags (Multi-select)
Add a Multi-select property named Tags.
Tags serve two purposes: skill level and topic. Use them to categorize resources so topic-specific filtered views work correctly.
Skill level tags: Beginner / Intermediate / Advanced
Topic tags — add what's relevant to your stack: JavaScript / TypeScript / Python / React / Node.js / CSS / SQL / Docker / Git / System Design / Clean Code / Data Science / Documentation / Testing / DevOps
Keep your tag list under 30 total. More than that and tags start overlapping — you'll forget which one you used on a specific resource and filtering becomes unreliable.
The JavaScript Courses view and Books to Read view both use Tags as filter conditions. Any tag you want to filter by later needs to be added to entries consistently.
Length (Number)
Add a Number property named Length.
This is the total number of lessons, chapters, modules, or sections in the resource. It's the denominator in the progress calculation.
How to set it per type:
- Course: total number of videos or modules
- Book: total number of chapters
- Tutorial: total number of sections or steps
- Article: set to 1 — articles are single-unit resources
If you don't know the exact number yet, estimate and update it later. The progress formula handles the calculation — you just need a reasonable denominator.
Learning Hours Log (Number)
Add a Number property named Learning Hours Log.
Track total hours spent on this resource. Update it manually after each study session — add to the existing number, don't overwrite it.
Over time this gives you a running record of where your learning hours actually go. A course with 10 hours logged that's still at 20% completion tells you something different than a course with 2 hours logged at the same progress.
Step 3: Create the Lessons Database
Before setting up the Lessons relation in Learning Resources, you need to build the database it connects to.
Create a second full-page database. Name it Lessons / Chapters / Course Modules.
Add these properties:
Property - Type - Purpose
Name - Title - The lesson or chapter name
Completed - Checkbox - Mark when done
Learning Resource - Relation - Links back to Learning Resources
When you create the relation in this database pointing to Learning Resources, toggle on "Show on Learning Resources" — this creates the bidirectional connection automatically.
How to use it: when you start a new course or book, add each lesson or chapter as a separate row in this database and link it to the parent resource. As you complete each one, check the Completed checkbox. The Progress formula in Learning Resources reads this count automatically.
Step 4: Add the Lessons Relation to Learning Resources
Back in your Learning Resources database, add a Relation property named Lessons.
When setting it up:
Search for and select your Lessons / Chapters / Course Modules database
Toggle on "Show on Learning Resources"
This creates a two-way relation. Each Learning Resource knows which lessons belong to it. Each lesson knows which resource it belongs to.
Step 5: Add the Daily Log Relation
Add a second Relation property named Daily Log.
Link this to your Daily Log database if you have one. This connects your learning activity to the days you actually worked on it — so when you look at a daily log entry, you can see which resources you touched that day, and when you look at a resource, you can see which days had activity on it.
If you don't have a Daily Log database yet, leave this property empty for now. Add it when you build one.
Step 6: Add the Two Formulas
These are the two formulas that make the database intelligent rather than just a list.
Formula 1: Is Done? (Checkbox)
Add a Formula property named Is Done?
Change the output type to Checkbox.
The formula:
prop("Status") == "Completed"
What it does: Returns a checked checkbox when Status is "Completed" and an unchecked checkbox when it's anything else.
Why use a formula instead of just reading the Status field directly: The Is Done? checkbox gives you a clean binary signal that works cleanly in rollups from other databases. If your Character Sheet or a Projects database needs to count completed learning resources, rolling up a checkbox is simpler and more reliable than filtering by a Select property's text value.
One thing to watch: The formula checks the exact string "Completed" — capital C. If your Status option is named differently, update the formula string to match.
Formula 2: Progress (Number)
Add a Formula property named Progress.
Change the output type to Number. In the number format settings, set it to display as a percentage.
The formula:
if(
empty(prop("Lessons")) or prop("Length") == 0,
0,
prop("Lessons").filter(
current.prop("Completed") == true
).length() / prop("Length")
)
What each part does:
if(empty(prop("Lessons")) or prop("Length") == 0, 0, — guard clause. If no lessons are linked yet or Length is 0, return 0 instead of a division error or a misleading percentage.
prop("Lessons").filter(current.prop("Completed") == true).length() — counts only the lessons marked as Completed in the related Lessons database. This is the numerator.
/ prop("Length") — divides completed lessons by the total length you entered manually. This is the denominator.
The result: A percentage from 0 to 1 that Notion displays as 0% to 100% in percentage format. Updates automatically every time you check off a lesson.
Why this approach works better than a manual percentage field: Manual percentage fields require you to remember to update them. This formula reads from actual lesson completion — so the progress number always reflects real work, not an estimate you set and forgot to change.
One thing to watch: Progress is based on completed lessons divided by the Length you entered manually. If Length is set to 10 but the course actually has 15 lessons, the progress will show 100% before you've finished. Keep Length accurate as you go through the resource.
Step 7: Build the Five Views
These five views give you different angles on the same data — each one answers a different question about your learning without you having to filter manually each time.
View 1: All Learning Resources (Table View)
This is your master view. Everything visible, nothing filtered.
Properties to show: Name, Type, Status, Tags, Link, Length, Progress, Learning Hours Log, Lessons, Daily Log
Sort: Name, ascending
Use this view for initial setup, bulk editing, and your monthly review when you want to see everything at once.
View 2: Active Learning (Gallery View)
View type: Gallery
Filter: Status ≠ Completed
Sort: Status, ascending
Properties shown on cards: Name, Status, Progress
This is your daily working view. It shows everything you haven't finished — both In Progress and To Read resources — sorted so In Progress appears before To Read.
The gallery format makes the Progress property visible as a progress bar on each card, giving you a visual read on how far along each active resource is without clicking into anything.
Keep this view clean. If it has more than five or six cards, you have too many active resources. Reduce to three In Progress items maximum — more than that and you're context switching between learning the same way you context switch between tasks.
View 3: Learning Pipeline (Board View)
View type: Board
Group by: Type
Filter: Status ≠ Completed
Sort: Progress, ascending
Hide empty groups: On
This view shows your incomplete resources organized by format type — Courses in one column, Books in another, Articles and Tutorials in theirs. Resources with the lowest progress appear at the top of each column.
Use it on Mondays for a weekly learning check. The column structure tells you immediately whether your learning is spread across formats or piled up in one area. Four courses in progress and zero books being read is a pattern worth noticing.
The ascending progress sort surfaces the resources you've barely started before the ones you're close to finishing — useful for deciding whether to push through something that's almost done or restart something you've stalled on.
View 4: JavaScript Courses (List View)
View type: List
Filters: Type = Course AND Tags contains JavaScript
Properties shown: Name, Tags
This is an example of a topic-specific filtered view. It shows only courses tagged with JavaScript, regardless of status — so you can see everything in that topic area at once, including completed ones.
Build similar views for any technology you're actively developing skills in. The pattern is always the same: Type = Course (or Book, or Tutorial) AND Tags contains [your topic].
Examples you might add based on your stack:
- Python Books: Type = Book AND Tags contains Python
- React Tutorials: Type = Tutorial AND Tags contains React
- System Design Resources: Tags contains System Design (any type)
View 5: Books to Read (List View)
View type: List
Filters: Type = Book AND Status = To Read
Properties shown: Name
Your reading backlog. Clean and minimal — just the titles, nothing else.
This view answers one question: what books haven't I started yet? When you finish a book and mark it Completed, it disappears from this view automatically. When you add a new book with Status = To Read, it appears automatically.
Build similar views for other types if the backlog gets large:
- Courses to Start: Type = Course AND Status = To Read
- Articles to Read: Type = Article AND Status = To Read
Step 8: Add Tags to Existing Resources and Test
Before the views are useful, the data needs to be accurate.
Go through your existing resources (or add a few test entries) and:
- Set the correct Type for each
- Set Status to To Read, In Progress, or Completed accurately
- Add at least one skill level tag (Beginner/Intermediate/Advanced) and one topic tag
- Fill in Length with the number of lessons, chapters, or sections
- Create lesson entries in the Lessons database for any In Progress resource and link them back
Once you have a few entries set up correctly, open each view and verify the filters are working. The Active Learning gallery should show only incomplete resources. The Learning Pipeline board should group by type with no Completed items. JavaScript Courses should show only items with both conditions met.
How to Use This System Day to Day
When you find a new resource:
Add it to Learning Resources with Status = To Read. Set Type, add Tags, fill in Length. Link added, resource captured, done.
When you start something:
Change Status to In Progress. Create the lesson entries in your Lessons database and link them to the resource. Now progress tracking is live.
During a study session:
Check off completed lessons in the Lessons database. Watch the Progress formula update automatically. Log your hours in Learning Hours Log — add to the existing number.
When you finish:
Change Status to Completed. Is Done? auto-checks. The resource disappears from Active Learning and Learning Pipeline. It stays visible in All Learning Resources as a permanent record.
Weekly (Monday, 5 minutes):
Open the Learning Pipeline board. Check if anything In Progress has stalled — low progress, no recent lesson completions. Decide honestly: restart it, pause it, or abandon it. Pull something from To Read into In Progress if you have fewer than three active items.
Why This Works Better Than a Simple List
A plain list of resources tells you what you want to learn. This system tells you where everything actually is.
The Progress formula reads from real lesson completion — not from an estimate you set and forgot to update. The Is Done? formula creates a reliable completion signal that works in rollups from other databases. The five views answer five different questions without any manual filtering on your part.
The lesson-level relation is the most important structural decision in the system. It means progress is earned, not estimated. You can't move the percentage by convincing yourself you remember the material. You move it by checking off the work.
If you want this database pre-built and connected to a complete developer workspace — including daily log integration, character sheet rollups, and the full DevHub system — the free version is available at no cost.
Free download, no credit card required.
What's been sitting on your learning list the longest without moving? Drop it in the comments.
Top comments (0)