# Capture template from file but only for new entries

**URL:** <https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114>\
**Category:** How To\
**Created:** [June 15, 2023, 11:52am UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114 "2023-06-15T11:52:38Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![iamkarlson](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/iamkarlson/32/1336_2.png) [@iamkarlson](https://org-roam.discourse.group/u/iamkarlson)\
**Post date:** [June 15, 2023, 11:52am UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114/1 "2023-06-15T11:52:38Z")

</div>

I would love to make some structured templates for different types of notes. However, once they created, I usually want to populate a section “Notes” from this nodes.  
For example, I have the following template:

```auto
          ("l" "technology" plain "* %?"
           :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" (file "templates/technology.org"))
           :target (file "%<%Y%m%d%H%M%S>-${slug}.org")
           :unnarrowed t)
          )

```

it would work like I wanted to, but it gives me the following error:

```auto
File 20230615134515-sandbox.org added to project /home/iamkarlson/braindb/ cache.
org-roam-capture--fill-template: Wrong type argument: char-or-string-p, (file "templates/technology.org")
Error running timer ‘org-reveal’: (wrong-type-argument number-or-marker-p nil) [2 times]

```

How can you define capture template in file but only if it’s a new node?

---

<div class="post-metadata">

**Author:** ![nobiot](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/nobiot/32/159_2.png) [@nobiot](https://org-roam.discourse.group/u/nobiot)\
**Post date:** [June 19, 2023, 7:42am UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114/2 "2023-06-19T07:42:58Z")

</div>

This [post](https://org-roam.discourse.group/t/read-capture-template-from-file/1869) might help you structure the variable correctly.

You don’t use `:if-new` and `:target` at the same time. They do the same thing. `:if-new` is old and not to be used any more; `:target` replaces it. I believe the former remains only for backward compatibility.

---

<div class="post-metadata">

**Author:** ![iamkarlson](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/iamkarlson/32/1336_2.png) [@iamkarlson](https://org-roam.discourse.group/u/iamkarlson)\
**Post date:** [July 4, 2023, 7:50am UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114/3 "2023-07-04T07:50:14Z")

</div>

I don’t think that these parameters address my problem. For new nodes only I want to fill some standard questions, and capture my notes at the end. For example, like a wikipedia has a “quick info” section with some basic details, and you need only _one_ of those. Even with `:target` parameter only - I cannot use file based templates.

I found a solution to use files for capture template here:

> <https://github.com/hlissner/.doom.d/blob/master/config.el#L138>

```auto
("n" "note" plain
           ,(format "#+title: ${title}\n%%[%s/template/note.org]" org-roam-directory)
           :target (file "note/%<%Y%m%d%H%M%S>-${slug}.org")
           :unnarrowed t)

```

But if I capture twice to the same node - the same template would be added twice, and I don’t want that.

---

<div class="post-metadata">

**Author:** ![nobiot](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/nobiot/32/159_2.png) [@nobiot](https://org-roam.discourse.group/u/nobiot)\
**Post date:** [July 4, 2023, 3:55pm UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114/4 "2023-07-04T15:55:04Z")

</div>

> [@iamkarlson](#):
>
> But if I capture twice to the same node - the same template would be added twice, and I don’t want that.

> [@iamkarlson](#):
>
> I would love to make some structured templates for different types of notes. However, once they created, I usually want to populate a section “Notes” from this nodes.

Like this? Not sure if I understand your problem correctly.

 ![Screenshot from 2023-07-04 13-02-48](https://global.discourse-cdn.com/free1/uploads/orgroam/original/2X/7/7c5b8525c8aa372ae1e077aaf3b2da8864394370.png)

```emacs-lisp
(setq org-roam-capture-templates
      '(("t" "technology" plain "** %?" ;; <= New notes in H2
         :target (file+head+olp "%<%Y%m%d%H%M%S>-${slug}.org" ;; <= file name
                                "(#+title: ${title})" ;; <= head (only once for file)
                                ("Notes")) ;; <= H1
         :unnarrowed t)))

```

---

<div class="post-metadata">

**Author:** ![nobiot](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/nobiot/32/159_2.png) [@nobiot](https://org-roam.discourse.group/u/nobiot)\
**Post date:** [July 4, 2023, 4:04pm UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114/5 "2023-07-04T16:04:28Z")

</div>

If you additionally want to get the template in a file, this works on my end:

```plaintext
(setq org-roam-capture-templates
      '(("t" "technology" plain (file "~/templates/technology.org") ;; <= New notes in H2
         :target (file+head+olp "%<%Y%m%d%H%M%S>-${slug}.org" ;; <= file name
                                "(#+title: ${title})" ;; <= head (only once for file)
                                ("Notes")) ;; <= H1
         :unnarrowed t)))

```

 ![image](https://global.discourse-cdn.com/free1/uploads/orgroam/original/2X/5/5ba4c0197dca4caeeac28848081ffa77f58adca9.png)

`~/templates/technology.org` looks like this:

```plaintext
** This is tech notes template
%?
*** Template section 1

*** Template section 2

```

---

<div class="post-metadata">

**Author:** ![iamkarlson](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/iamkarlson/32/1336_2.png) [@iamkarlson](https://org-roam.discourse.group/u/iamkarlson)\
**Post date:** [July 4, 2023, 5:18pm UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114/6 "2023-07-04T17:18:35Z")

</div>

> [@nobiot](#):
>
> “(#+title: ${title})” ;; \<= head (only once for  
> (“Notes”)) ;; \<= H1
> 
> ```auto
> 
> ```

I want this coming from the file.

---

<div class="post-metadata">

**Author:** ![nobiot](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/nobiot/32/159_2.png) [@nobiot](https://org-roam.discourse.group/u/nobiot)\
**Post date:** [July 4, 2023, 5:46pm UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114/7 "2023-07-04T17:46:29Z")

</div>

See my later post

---

<div class="post-metadata">

**Author:** ![iamkarlson](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/iamkarlson/32/1336_2.png) [@iamkarlson](https://org-roam.discourse.group/u/iamkarlson)\
**Post date:** [July 6, 2023, 6:40pm UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114/8 "2023-07-06T18:40:52Z")

</div>

In your later post you get template from the file for all new captures, and base template for the first file creation comes from the config, and I want exactly the opposite.

---

<div class="post-metadata">

**Author:** ![nobiot](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/nobiot/32/159_2.png) [@nobiot](https://org-roam.discourse.group/u/nobiot)\
**Post date:** [July 7, 2023, 5:00pm UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114/9 "2023-07-07T17:00:18Z")

</div>

I dug a little deeper by going through the code. I don’t think this is documented, but reading the code, I have realized that you can use a function name instead of a string. So this below works. (If you are interested in where to look, it’s function `org-roam-capture--fill-template`).

 ![Screenshot from 2023-07-07 18-48-56](https://global.discourse-cdn.com/free1/uploads/orgroam/original/2X/3/3b3e1d39a2e811ab89141300372655c1be8ff813.png)

```plaintext
(setq org-roam-capture-templates
      '(("t" "technology" plain "** %?" ;; <= New notes in H2
         :target (file+head+olp my/get-note-file-name ;; <= file name
                                my/get-tech-head ;; <= head (only once for file)
                                ("Note")) ;; H1
         :unnarrowed t)))

(defun my/get-note-file-name ()
  (with-temp-buffer
    (insert-file "~/Documents/temp/filename.org")
    (buffer-substring-no-properties (point-min) (point-max))))

(defun my/get-tech-head ()
  (with-temp-buffer
    (insert-file "~/Documents/temp/head.org")
    (buffer-substring-no-properties (point-min) (point-max))))

```

`~/Documents/temp/filename.org`

```plaintext
%<%Y%m%d%H%M%S>-${slug}.org

```

`~/Documents/temp/head.org`

```plaintext
#+title: ${title}
#+author: Name

* Note
:properties:
:CATEGORY: notes
:end:

```

---

<div class="post-metadata">

**Author:** ![iamkarlson](https://yyz2.discourse-cdn.com/free1/user_avatar/org-roam.discourse.group/iamkarlson/32/1336_2.png) [@iamkarlson](https://org-roam.discourse.group/u/iamkarlson)\
**Post date:** [May 6, 2025, 6:15pm UTC](https://org-roam.discourse.group/t/capture-template-from-file-but-only-for-new-entries/3114/10 "2025-05-06T18:15:26Z")

</div>

I made it work like I wanted. Here’s a function I use to read the content of the file from the given directory as a string:

```auto
(defun my/read-file (file)
  "Return the contents of FILE as a string."
  (with-temp-buffer
    (insert-file-contents file)
    (buffer-string)))

```

Then I can use it to read my template from another directory:

```auto
  (setq org-roam-capture-templates
        `(
          ("d" "default" plain
           "* %?"
           :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org"
                              "#+title: ${title}\n")
           :target (file "%<%Y%m%d%H%M%S>-${slug}.org")
           :unnarrowed t)

          ;; Technology or tool
          ("t" "technology" plain "* %?"
           :if-new (file+head
                    "%<%Y%m%d%H%M%S>-${slug}.org"
                    ,(my/read-file (concat org-roam-directory "templates/technology.org"))
                    )
           :target (file "%<%Y%m%d%H%M%S>-${slug}.org")
           :unnarrowed t)))

```

I wanted to achieve such behaviour because my emacs config is in public repo, and my notes are in a private one. I didn’t want to include templates for my private notes in public 🙂
