diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/importer/TemplateImporter.java b/src/main/java/de/deadlocker8/budgetmaster/database/importer/TemplateImporter.java
new file mode 100644
index 0000000000000000000000000000000000000000..68da11b65488a70f26d5c6c4f76e43b9665a4985
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/importer/TemplateImporter.java
@@ -0,0 +1,55 @@
+package de.deadlocker8.budgetmaster.database.importer;
+
+import de.deadlocker8.budgetmaster.services.EntityType;
+import de.deadlocker8.budgetmaster.templategroup.TemplateGroup;
+import de.deadlocker8.budgetmaster.templates.Template;
+import de.deadlocker8.budgetmaster.templates.TemplateRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.MessageFormat;
+
+public class TemplateImporter extends ItemImporter<Template>
+{
+	private static final Logger LOGGER = LoggerFactory.getLogger(TemplateImporter.class);
+
+	private final TagImporter tagImporter;
+	private final TemplateGroup defaultTemplateGroup;
+	private final boolean alwaysAssignDefaultTemplateGroup;
+
+	public TemplateImporter(TemplateRepository templateRepository, TagImporter tagImporter, TemplateGroup defaultTemplateGroup, boolean alwaysAssignDefaultTemplateGroup)
+	{
+		super(templateRepository, EntityType.TEMPLATE);
+		this.tagImporter = tagImporter;
+		this.defaultTemplateGroup = defaultTemplateGroup;
+		this.alwaysAssignDefaultTemplateGroup = alwaysAssignDefaultTemplateGroup;
+	}
+
+	@Override
+	protected int importSingleItem(Template template)
+	{
+		if(!(repository instanceof TemplateRepository repository))
+		{
+			throw new IllegalArgumentException("Invalid repository type");
+		}
+
+		LOGGER.debug(MessageFormat.format("Importing template with templateName: {0})", template.getTemplateName()));
+
+		tagImporter.importItems(template.getTags());
+		template.setID(null);
+
+		if(alwaysAssignDefaultTemplateGroup || template.getTemplateGroup() == null)
+		{
+			template.setTemplateGroup(defaultTemplateGroup);
+		}
+
+		final Template newTemplate = repository.save(template);
+		return newTemplate.getID();
+	}
+
+	@Override
+	protected String getNameForItem(Template item)
+	{
+		return item.getTemplateName();
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/importer/TransactionImporter.java b/src/main/java/de/deadlocker8/budgetmaster/database/importer/TransactionImporter.java
index 896573e4b92d1536d23644b9cba30c058f0a1c3a..462bb86e7b0807412dd18c7d1fd5e4ae9dbcd292 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/importer/TransactionImporter.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/importer/TransactionImporter.java
@@ -29,10 +29,11 @@ public class TransactionImporter extends ItemImporter<Transaction>
 		}
 
 		LOGGER.debug(MessageFormat.format("Importing transaction with name: {0}, date: {1}", transaction.getName(), transaction.getDate()));
+
 		tagImporter.importItems(transaction.getTags());
 		transaction.setID(null);
-		final Transaction newTransaction = repository.save(transaction);
 
+		final Transaction newTransaction = repository.save(transaction);
 		return newTransaction.getID();
 	}
 
diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/ImportService.java b/src/main/java/de/deadlocker8/budgetmaster/services/ImportService.java
index 190c101f40f5ca1a41c0fc7c02c9aa1250a0e711..eabdb24495f3620b0cf95234cfc696c72dc0b249 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/services/ImportService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/services/ImportService.java
@@ -101,7 +101,8 @@ public class ImportService
 
 		if(importTemplates)
 		{
-			importResultItems.add(importTemplates(importTemplateGroups));
+			final TemplateGroup defaultTemplateGroup = templateGroupRepository.findFirstByType(TemplateGroupType.DEFAULT);
+			importResultItems.add(new TemplateImporter(templateRepository, tagImporter, defaultTemplateGroup, !importTemplateGroups).importItems(database.getTemplates()));
 		}
 		else
 		{
@@ -228,41 +229,4 @@ public class ImportService
 
 		return updatedItems;
 	}
-
-	private ImportResultItem importTemplates(Boolean importTemplateGroups)
-	{
-		List<Template> templates = database.getTemplates();
-		LOGGER.debug(MessageFormat.format("Importing {0} templates...", templates.size()));
-
-		int numberOfImportedTemplates = 0;
-
-		for(int i = 0; i < templates.size(); i++)
-		{
-			Template template = templates.get(i);
-			try
-			{
-				LOGGER.debug(MessageFormat.format("Importing template {0}/{1} (templateName: {2})", i + 1, templates.size(), template.getTemplateName()));
-//				updateTagsForItem(template);
-				template.setID(null);
-
-				if(!importTemplateGroups || template.getTemplateGroup() == null)
-				{
-					template.setTemplateGroup(templateGroupRepository.findFirstByType(TemplateGroupType.DEFAULT));
-				}
-
-				templateRepository.save(template);
-
-				numberOfImportedTemplates++;
-			}
-			catch(Exception e)
-			{
-				final String errorMessage = MessageFormat.format("Error while importing template with name \"{0}\"", template.getTemplateName());
-				LOGGER.error(errorMessage, e);
-				collectedErrorMessages.add(formatErrorMessage(errorMessage, e));
-			}
-		}
-
-		LOGGER.debug(MessageFormat.format("Importing templates DONE ({0}/{1})", numberOfImportedTemplates, templates.size()));
-		return new ImportResultItem(EntityType.TEMPLATE, numberOfImportedTemplates, templates.size(), collectedErrorMessages);
-	}
 }
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/importer/TemplateImporterTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/importer/TemplateImporterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f5df78182073a456ae3c7f0d190aa59de5693bff
--- /dev/null
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/importer/TemplateImporterTest.java
@@ -0,0 +1,316 @@
+package de.deadlocker8.budgetmaster.unit.database.importer;
+
+import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.accounts.AccountRepository;
+import de.deadlocker8.budgetmaster.accounts.AccountType;
+import de.deadlocker8.budgetmaster.categories.Category;
+import de.deadlocker8.budgetmaster.categories.CategoryRepository;
+import de.deadlocker8.budgetmaster.categories.CategoryType;
+import de.deadlocker8.budgetmaster.database.importer.TagImporter;
+import de.deadlocker8.budgetmaster.database.importer.TemplateImporter;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconRepository;
+import de.deadlocker8.budgetmaster.services.EntityType;
+import de.deadlocker8.budgetmaster.services.ImportResultItem;
+import de.deadlocker8.budgetmaster.tags.Tag;
+import de.deadlocker8.budgetmaster.tags.TagRepository;
+import de.deadlocker8.budgetmaster.templategroup.TemplateGroup;
+import de.deadlocker8.budgetmaster.templategroup.TemplateGroupRepository;
+import de.deadlocker8.budgetmaster.templategroup.TemplateGroupType;
+import de.deadlocker8.budgetmaster.templates.Template;
+import de.deadlocker8.budgetmaster.templates.TemplateRepository;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@ExtendWith(SpringExtension.class)
+@DataJpaTest
+@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
+class TemplateImporterTest
+{
+	@Autowired
+	private AccountRepository accountRepository;
+
+	@Autowired
+	private CategoryRepository categoryRepository;
+
+	@Autowired
+	private TemplateRepository templateRepository;
+
+	@Autowired
+	private TagRepository tagRepository;
+
+	@Autowired
+	private IconRepository iconRepository;
+
+	@Autowired
+	private TemplateGroupRepository templateGroupRepository;
+
+	@Test
+	void test_importTemplate()
+	{
+		Category category = new Category("Awesome Category", "#ff0000", CategoryType.CUSTOM);
+		category = categoryRepository.save(category);
+
+		Account account = new Account("Awesome Account", AccountType.CUSTOM);
+		account = accountRepository.save(account);
+
+		Account transferAccount = new Account("Transfer Account", AccountType.CUSTOM);
+		transferAccount = accountRepository.save(transferAccount);
+
+		Icon icon = new Icon("fas fa-icons");
+		icon = iconRepository.save(icon);
+
+		final Template template = new Template();
+		template.setID(15);
+		template.setTemplateName("My awesome template");
+		template.setName("My transaction");
+		template.setAmount(-100);
+		template.setIsExpenditure(true);
+		template.setCategory(category);
+		template.setAccount(account);
+		template.setTags(List.of());
+		template.setDescription("Lorem Ipsum");
+		template.setIconReference(icon);
+		template.setTransferAccount(transferAccount);
+
+		TemplateGroup defaultTemplateGroup = new TemplateGroup("Default group", TemplateGroupType.DEFAULT);
+		defaultTemplateGroup = templateGroupRepository.save(defaultTemplateGroup);
+
+		final TagImporter tagImporter = new TagImporter(tagRepository);
+		final TemplateImporter importer = new TemplateImporter(templateRepository, tagImporter, defaultTemplateGroup, false);
+		final ImportResultItem resultItem = importer.importItems(List.of(template));
+
+		final ImportResultItem expected = new ImportResultItem(EntityType.TEMPLATE, 1, 1, List.of());
+		assertThat(resultItem).isEqualTo(expected);
+
+		final List<Template> templates = templateRepository.findAll();
+		assertThat(templates).hasSize(1);
+		final Template actualTemplate = templates.get(0);
+		assertThat(actualTemplate)
+				.hasFieldOrPropertyWithValue("ID", 1)
+				.hasFieldOrPropertyWithValue("templateName", "My awesome template")
+				.hasFieldOrPropertyWithValue("name", "My transaction")
+				.hasFieldOrPropertyWithValue("amount", -100)
+				.hasFieldOrPropertyWithValue("isExpenditure", true)
+				.hasFieldOrPropertyWithValue("category", category)
+				.hasFieldOrPropertyWithValue("account", account)
+				.hasFieldOrPropertyWithValue("description", "Lorem Ipsum")
+				.hasFieldOrPropertyWithValue("transferAccount", transferAccount)
+				.hasFieldOrPropertyWithValue("templateGroup", defaultTemplateGroup)
+				.hasFieldOrPropertyWithValue("iconReference", icon);
+		assertThat(actualTemplate.getTags()).isEmpty();
+	}
+
+	@Test
+	void test_importTemplateWithTags()
+	{
+		Category category = new Category("Awesome Category", "#ff0000", CategoryType.CUSTOM);
+		category = categoryRepository.save(category);
+
+		Account account = new Account("Awesome Account", AccountType.CUSTOM);
+		account = accountRepository.save(account);
+
+		Icon icon = new Icon("fas fa-icons");
+		icon = iconRepository.save(icon);
+
+		final Template template = new Template();
+		template.setID(15);
+		template.setTemplateName("My awesome template");
+		template.setName("My transaction");
+		template.setAmount(-100);
+		template.setIsExpenditure(true);
+		template.setCategory(category);
+		template.setAccount(account);
+		template.setTags(List.of());
+		template.setDescription("Lorem Ipsum");
+		template.setIconReference(icon);
+
+		final Tag tag1 = new Tag("0815");
+		tag1.setID(1);
+		final Tag tag2 = new Tag("Apple Pie");
+		tag2.setID(2);
+		template.setTags(List.of(tag1, tag2));
+
+		TemplateGroup defaultTemplateGroup = new TemplateGroup("Default group", TemplateGroupType.DEFAULT);
+		defaultTemplateGroup = templateGroupRepository.save(defaultTemplateGroup);
+
+		final TagImporter tagImporter = new TagImporter(tagRepository);
+		final TemplateImporter importer = new TemplateImporter(templateRepository, tagImporter, defaultTemplateGroup, false);
+		final ImportResultItem resultItem = importer.importItems(List.of(template));
+
+		final ImportResultItem expected = new ImportResultItem(EntityType.TEMPLATE, 1, 1, List.of());
+		assertThat(resultItem).isEqualTo(expected);
+
+		final List<Template> templates = templateRepository.findAll();
+		assertThat(templates).hasSize(1);
+		final Template actualTemplate = templates.get(0);
+		assertThat(actualTemplate)
+				.hasFieldOrPropertyWithValue("ID", 1)
+				.hasFieldOrPropertyWithValue("templateName", "My awesome template")
+				.hasFieldOrPropertyWithValue("name", "My transaction")
+				.hasFieldOrPropertyWithValue("amount", -100)
+				.hasFieldOrPropertyWithValue("isExpenditure", true)
+				.hasFieldOrPropertyWithValue("category", category)
+				.hasFieldOrPropertyWithValue("account", account)
+				.hasFieldOrPropertyWithValue("description", "Lorem Ipsum")
+				.hasFieldOrPropertyWithValue("transferAccount", null)
+				.hasFieldOrPropertyWithValue("templateGroup", defaultTemplateGroup)
+				.hasFieldOrPropertyWithValue("iconReference", icon);
+
+		final Tag expectedTag1 = new Tag("0815");
+		expectedTag1.setID(1);
+		final Tag expectedTag2 = new Tag("Apple Pie");
+		expectedTag2.setID(2);
+		assertThat(actualTemplate.getTags())
+				.containsExactly(expectedTag1, expectedTag2);
+	}
+
+	@Test
+	void test_test_importMultipleTemplatesWithSomeSimilarTags()
+	{
+		Category category = new Category("Awesome Category", "#ff0000", CategoryType.CUSTOM);
+		category = categoryRepository.save(category);
+
+		Account account = new Account("Awesome Account", AccountType.CUSTOM);
+		account = accountRepository.save(account);
+
+		Icon icon = new Icon("fas fa-icons");
+		icon = iconRepository.save(icon);
+
+		final Tag tag1 = new Tag("0815");
+		tag1.setID(1);
+		final Tag tag2 = new Tag("Apple Pie");
+		tag2.setID(2);
+
+		final Template template = new Template();
+		template.setID(15);
+		template.setTemplateName("My awesome template");
+		template.setName("My transaction");
+		template.setAmount(-100);
+		template.setIsExpenditure(true);
+		template.setCategory(category);
+		template.setAccount(account);
+		template.setTags(List.of());
+		template.setDescription("Lorem Ipsum");
+		template.setIconReference(icon);
+		template.setTags(List.of(tag1, tag2));
+
+		final Template template2 = new Template();
+		template2.setID(16);
+		template2.setTemplateName("My awesome template 2");
+		template2.setIsExpenditure(true);
+		template2.setTags(List.of());
+		template2.setDescription("Lorem Ipsum");
+		template2.setIconReference(icon);
+		template2.setTags(List.of(tag1));
+
+		TemplateGroup defaultTemplateGroup = new TemplateGroup("Default group", TemplateGroupType.DEFAULT);
+		defaultTemplateGroup = templateGroupRepository.save(defaultTemplateGroup);
+
+		final TagImporter tagImporter = new TagImporter(tagRepository);
+		final TemplateImporter importer = new TemplateImporter(templateRepository, tagImporter, defaultTemplateGroup, false);
+		final ImportResultItem resultItem = importer.importItems(List.of(template, template2));
+
+		final ImportResultItem expected = new ImportResultItem(EntityType.TEMPLATE, 2, 2, List.of());
+		assertThat(resultItem).isEqualTo(expected);
+
+		final List<Template> templates = templateRepository.findAll();
+		assertThat(templates).hasSize(2);
+		final Template actualTemplate = templates.get(0);
+		assertThat(actualTemplate)
+				.hasFieldOrPropertyWithValue("ID", 1)
+				.hasFieldOrPropertyWithValue("templateName", "My awesome template");
+
+		final Tag expectedTag1 = new Tag("0815");
+		expectedTag1.setID(1);
+		final Tag expectedTag2 = new Tag("Apple Pie");
+		expectedTag2.setID(2);
+		assertThat(actualTemplate.getTags())
+				.containsExactly(expectedTag1, expectedTag2);
+
+		final Template actualTemplate2 = templates.get(1);
+		assertThat(actualTemplate2)
+				.hasFieldOrPropertyWithValue("ID", 2)
+				.hasFieldOrPropertyWithValue("templateName", "My awesome template 2");
+
+		assertThat(actualTemplate2.getTags())
+				.containsExactly(expectedTag1);
+
+
+		assertThat(tagRepository.findAll()).hasSize(2);
+	}
+
+	@Test
+	void test_importTemplateWithTemplateGroup()
+	{
+		final Template template = new Template();
+		template.setID(15);
+		template.setTemplateName("My awesome template");
+		template.setName("My transaction");
+		template.setIsExpenditure(true);
+		template.setTags(List.of());
+
+		TemplateGroup templateGroup = new TemplateGroup("My group", TemplateGroupType.CUSTOM);
+		templateGroup = templateGroupRepository.save(templateGroup);
+		template.setTemplateGroup(templateGroup);
+
+		TemplateGroup defaultTemplateGroup = new TemplateGroup("Default group", TemplateGroupType.DEFAULT);
+		defaultTemplateGroup = templateGroupRepository.save(defaultTemplateGroup);
+
+		final TagImporter tagImporter = new TagImporter(tagRepository);
+		final TemplateImporter importer = new TemplateImporter(templateRepository, tagImporter, defaultTemplateGroup, false);
+		final ImportResultItem resultItem = importer.importItems(List.of(template));
+
+		final ImportResultItem expected = new ImportResultItem(EntityType.TEMPLATE, 1, 1, List.of());
+		assertThat(resultItem).isEqualTo(expected);
+
+		final List<Template> templates = templateRepository.findAll();
+		assertThat(templates).hasSize(1);
+		final Template actualTemplate = templates.get(0);
+		assertThat(actualTemplate)
+				.hasFieldOrPropertyWithValue("ID", 1)
+				.hasFieldOrPropertyWithValue("templateGroup", templateGroup);
+		assertThat(actualTemplate.getTags()).isEmpty();
+	}
+
+	@Test
+	void test_importTemplateAlwaysAssignDefaultTemplateGroup()
+	{
+		final Template template = new Template();
+		template.setID(15);
+		template.setTemplateName("My awesome template");
+		template.setName("My transaction");
+		template.setIsExpenditure(true);
+		template.setTags(List.of());
+
+		TemplateGroup templateGroup = new TemplateGroup("My group", TemplateGroupType.CUSTOM);
+		templateGroup = templateGroupRepository.save(templateGroup);
+		template.setTemplateGroup(templateGroup);
+
+		TemplateGroup defaultTemplateGroup = new TemplateGroup("Default group", TemplateGroupType.DEFAULT);
+		defaultTemplateGroup = templateGroupRepository.save(defaultTemplateGroup);
+
+		final TagImporter tagImporter = new TagImporter(tagRepository);
+		final TemplateImporter importer = new TemplateImporter(templateRepository, tagImporter, defaultTemplateGroup, true);
+		final ImportResultItem resultItem = importer.importItems(List.of(template));
+
+		final ImportResultItem expected = new ImportResultItem(EntityType.TEMPLATE, 1, 1, List.of());
+		assertThat(resultItem).isEqualTo(expected);
+
+		final List<Template> templates = templateRepository.findAll();
+		assertThat(templates).hasSize(1);
+		final Template actualTemplate = templates.get(0);
+		assertThat(actualTemplate)
+				.hasFieldOrPropertyWithValue("ID", 1)
+				.hasFieldOrPropertyWithValue("templateGroup", defaultTemplateGroup);
+		assertThat(actualTemplate.getTags()).isEmpty();
+	}
+}
\ No newline at end of file