diff --git a/pkg/references/reference_test.go b/pkg/references/reference_test.go
index 5e79de47ab96cc9e48b8ba0eb644f9519e9ee914..c44064921c1f291f5d627fc5a1a7bdff0477e1a9 100644
--- a/pkg/references/reference_test.go
+++ b/pkg/references/reference_test.go
@@ -2,9 +2,11 @@ package references
 
 import (
 	"context"
+	"fmt"
 	"testing"
 
 	"git.perx.ru/perxis/perxis-go/pkg/expr"
+	"github.com/mitchellh/mapstructure"
 	"github.com/stretchr/testify/require"
 )
 
@@ -39,3 +41,18 @@ func TestReference_InExpr(t *testing.T) {
 		})
 	}
 }
+
+func TestReference_encode(t *testing.T) {
+	var result map[string]any
+	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{TagName: "json", Result: &result})
+	require.NoError(t, err)
+
+	err = dec.Decode(&Reference{
+		ID:           "ref_id",
+		CollectionID: "coll_id",
+		Disabled:     false,
+	})
+	require.NoError(t, err)
+
+	fmt.Println(result)
+}
diff --git a/template/builder.go b/template/builder.go
index 64530be62337de21dc5b93956df261ce5211a302..21d35d3497c7167e066ef1dedecb9cb3751a6d42 100644
--- a/template/builder.go
+++ b/template/builder.go
@@ -3,7 +3,9 @@ package template
 import (
 	"bytes"
 	"context"
-	"text/template"
+	templhtml "html/template"
+	"io"
+	templtext "text/template"
 
 	"git.perx.ru/perxis/perxis-go/pkg/collections"
 	"git.perx.ru/perxis/perxis-go/pkg/content"
@@ -11,13 +13,20 @@ import (
 	"git.perx.ru/perxis/perxis-go/pkg/spaces"
 )
 
-type Builder struct {
+type Executor[T any] interface {
+	Parse(text string) (T, error)
+	Execute(w io.Writer, data any) error
+}
+
+type Builder[T Executor[T]] struct {
+	template func(string) T
+
 	ctx     context.Context
 	cnt     *content.Content
 	SpaceID string
 	EnvID   string
 	CollID  string
-	data    map[string]interface{}
+	data    map[string]any
 
 	// Для кеширования запросов
 	space       *spaces.Space
@@ -25,30 +34,48 @@ type Builder struct {
 	collection  *collections.Collection
 }
 
-func NewBuilder(cnt *content.Content, space, env, col string) *Builder {
-	return &Builder{
+func NewBuilder(cnt *content.Content, space, env, col string) Builder[*templtext.Template] {
+	b := Builder[*templtext.Template]{
 		ctx:     context.Background(),
 		cnt:     cnt,
 		SpaceID: space,
 		EnvID:   env,
 		CollID:  col,
 	}
+	b.template = func(name string) *templtext.Template {
+		return templtext.New(name).Funcs(b.getFuncs())
+	}
+	return b
 }
 
-func (b *Builder) getFuncs() template.FuncMap {
-	return template.FuncMap{
+func NewHTMLBuilder(cnt *content.Content, space, env, col string) Builder[*templhtml.Template] {
+	b := Builder[*templhtml.Template]{
+		ctx:     context.Background(),
+		cnt:     cnt,
+		SpaceID: space,
+		EnvID:   env,
+		CollID:  col,
+	}
+	b.template = func(name string) *templhtml.Template {
+		return templhtml.New(name).Funcs(b.getFuncs())
+	}
+	return b
+}
+
+func (b *Builder[T]) getFuncs() map[string]any {
+	return map[string]any{
 		"lookup": getLookup(b),
 		"system": getSystem(b),
 	}
 }
 
-func (b *Builder) WithData(data map[string]interface{}) *Builder {
+func (b *Builder[T]) WithData(data map[string]interface{}) *Builder[T] {
 	bld := *b
 	bld.data = data
 	return &bld
 }
 
-func (b *Builder) WithKV(kv ...any) *Builder {
+func (b *Builder[T]) WithKV(kv ...any) *Builder[T] {
 	bld := *b
 	if bld.data == nil {
 		bld.data = make(map[string]interface{}, 10)
@@ -63,33 +90,29 @@ func (b *Builder) WithKV(kv ...any) *Builder {
 	return &bld
 }
 
-func (b *Builder) GetData() map[string]interface{} {
+func (b *Builder[T]) GetData() map[string]interface{} {
 	return b.data
 }
 
-func (b *Builder) WithSpace(space, env string) *Builder {
+func (b *Builder[T]) WithSpace(space, env string) *Builder[T] {
 	bld := *b
 	bld.SpaceID = space
 	bld.EnvID = env
 	return &bld
 }
 
-func (b *Builder) WithContext(ctx context.Context) *Builder {
+func (b *Builder[T]) WithContext(ctx context.Context) *Builder[T] {
 	bld := *b
 	bld.ctx = ctx
 	return &bld
 }
 
-func (b *Builder) Context() context.Context {
+func (b *Builder[T]) Context() context.Context {
 	return b.ctx
 }
 
-func (b *Builder) Template() *template.Template {
-	return template.New("main").Funcs(b.getFuncs())
-}
-
-func (b *Builder) Execute(str string, data ...any) (string, error) {
-	t := b.Template()
+func (b *Builder[T]) Execute(str string, data ...any) (string, error) {
+	t := b.template("main")
 	buf := new(bytes.Buffer)
 	t, err := t.Parse(str)
 	if err != nil {
@@ -101,8 +124,8 @@ func (b *Builder) Execute(str string, data ...any) (string, error) {
 	return buf.String(), nil
 }
 
-func (b *Builder) ExecuteList(str []string, data ...any) ([]string, error) {
-	t := b.Template()
+func (b *Builder[T]) ExecuteList(str []string, data ...any) ([]string, error) {
+	t := b.template("main")
 	result := make([]string, len(str))
 	buffer := new(bytes.Buffer)
 	for i, tmpl := range str {
@@ -122,7 +145,7 @@ func (b *Builder) ExecuteList(str []string, data ...any) ([]string, error) {
 	return result, nil
 }
 
-func (b *Builder) ExecuteMap(str map[string]interface{}, data ...any) (map[string]interface{}, error) {
+func (b *Builder[T]) ExecuteMap(str map[string]interface{}, data ...any) (map[string]interface{}, error) {
 	result := make(map[string]interface{}, len(str))
 	for k, v := range str {
 		switch t := v.(type) {
@@ -150,7 +173,7 @@ func (b *Builder) ExecuteMap(str map[string]interface{}, data ...any) (map[strin
 	return result, nil
 }
 
-func (b *Builder) getData(data ...any) any {
+func (b *Builder[T]) getData(data ...any) any {
 	if len(data) == 0 {
 		return b.data
 	}
diff --git a/template/builder_test.go b/template/builder_test.go
index 128f706423f3ecc67097a76b8926fbed619eb1ce..2a259cde0f81bd1f8c438905d55ad6b9cfcd9e08 100644
--- a/template/builder_test.go
+++ b/template/builder_test.go
@@ -19,14 +19,15 @@ import (
 
 func TestBuilder_Execute(t *testing.T) {
 	tests := []struct {
-		name    string
-		SpaceID string
-		EnvID   string
-		CollID  string
-		str     string
-		data    any
-		want    any
-		wantErr bool
+		name        string
+		SpaceID     string
+		EnvID       string
+		CollID      string
+		str         string
+		data        any
+		want        any
+		htmlBuilder bool
+		wantErr     bool
 
 		getCnt func() (cnt *content.Content, assertExpectations func(t *testing.T))
 	}{
@@ -112,6 +113,7 @@ func TestBuilder_Execute(t *testing.T) {
 			return &content.Content{Collections: collsSvc}, func(t *testing.T) { collsSvc.AssertExpectations(t) }
 		}, str: "{{ system.Collection.Name }}", want: "cars", wantErr: false},
 		{name: "system without account", SpaceID: "space", str: "hello {{ system.Organization.Name }}", want: "", wantErr: true},
+		{name: "with html builder", str: "{{ . }}", data: "<script>alert(localStorage.secret)</script>", want: "&lt;script&gt;alert(localStorage.secret)&lt;/script&gt;", htmlBuilder: true, wantErr: false},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -122,15 +124,18 @@ func TestBuilder_Execute(t *testing.T) {
 				defer checkFn(t)
 			}
 
-			b := &Builder{
-				ctx:     context.Background(),
-				cnt:     cnt,
-				SpaceID: tt.SpaceID,
-				EnvID:   tt.EnvID,
-				CollID:  tt.CollID,
+			var (
+				got string
+				err error
+			)
+			if tt.htmlBuilder {
+				b := NewHTMLBuilder(cnt, tt.SpaceID, tt.EnvID, tt.CollID)
+				got, err = b.Execute(tt.str, tt.data)
+			} else {
+				b := NewBuilder(cnt, tt.SpaceID, tt.EnvID, tt.CollID)
+				got, err = b.Execute(tt.str, tt.data)
 			}
 
-			got, err := b.Execute(tt.str, tt.data)
 			if tt.wantErr == true {
 				assert.Error(t, err)
 			} else {
@@ -191,12 +196,7 @@ func TestBuilder_ExecuteList(t *testing.T) {
 			if tt.itemsCall != nil {
 				tt.itemsCall(itemsSvc)
 			}
-			b := &Builder{
-				ctx:     context.Background(),
-				cnt:     &content.Content{Items: itemsSvc},
-				SpaceID: tt.SpaceID,
-				EnvID:   tt.EnvID,
-			}
+			b := NewBuilder(&content.Content{Items: itemsSvc}, tt.SpaceID, tt.EnvID, "")
 
 			got, err := b.ExecuteList(tt.str, tt.data)
 			if tt.wantErr == true {
@@ -260,12 +260,7 @@ func TestBuilder_ExecuteMap(t *testing.T) {
 			if tt.itemsCall != nil {
 				tt.itemsCall(itemsSvc)
 			}
-			b := &Builder{
-				ctx:     context.Background(),
-				cnt:     &content.Content{Items: itemsSvc},
-				SpaceID: tt.SpaceID,
-				EnvID:   tt.EnvID,
-			}
+			b := NewBuilder(&content.Content{Items: itemsSvc}, tt.SpaceID, tt.EnvID, "")
 
 			got, err := b.ExecuteMap(tt.str, tt.data)
 			if tt.wantErr == true {
diff --git a/template/funcs.go b/template/funcs.go
index 0c320ad139e964f002b691ce097b24e70e6cfaf3..3d69e45d0f4a4127341b757e8d8d8ddedcc61fb0 100644
--- a/template/funcs.go
+++ b/template/funcs.go
@@ -9,7 +9,7 @@ import (
 // getLookup возвращает функцию для шаблонизатора для получения значений из записи коллекции
 // name указывается в виде "<collection id>.<item id>.<field>"
 // Использование в шаблонах:  {{ lookup "secrets.key.value" }}
-func getLookup(b *Builder) any {
+func getLookup[T Executor[T]](b *Builder[T]) any {
 	return func(name string) (any, error) {
 		parsedName := strings.Split(name, ".")
 		if len(parsedName) < 3 {
@@ -36,8 +36,8 @@ func getLookup(b *Builder) any {
 
 // getSys возвращает функцию получения System
 // Использование в шаблонах: {{ system.SpaceID }}
-func getSystem(b *Builder) any {
-	return func() *System {
-		return &System{builder: b}
+func getSystem[T Executor[T]](b *Builder[T]) any {
+	return func() *System[T] {
+		return &System[T]{builder: b}
 	}
 }
diff --git a/template/system.go b/template/system.go
index c7dda43f08c852f590cd7cfa16ec00709423c7a3..d6e66616e7dd0e2fae251dbc58b8ff0e83998a7a 100644
--- a/template/system.go
+++ b/template/system.go
@@ -6,23 +6,23 @@ import (
 	"git.perx.ru/perxis/perxis-go/pkg/spaces"
 )
 
-type System struct {
-	builder *Builder
+type System[T Executor[T]] struct {
+	builder *Builder[T]
 }
 
-func (s *System) SpaceID() string {
+func (s *System[T]) SpaceID() string {
 	return s.builder.SpaceID
 }
 
-func (s *System) EnvID() string {
+func (s *System[T]) EnvID() string {
 	return s.builder.EnvID
 }
 
-func (s *System) CollectionID() string {
+func (s *System[T]) CollectionID() string {
 	return s.builder.CollID
 }
 
-func (s *System) Space() (*spaces.Space, error) {
+func (s *System[T]) Space() (*spaces.Space, error) {
 	if s.builder.space != nil {
 		return s.builder.space, nil
 	}
@@ -32,7 +32,7 @@ func (s *System) Space() (*spaces.Space, error) {
 	return s.builder.space, err
 }
 
-func (s *System) Environment() (*environments.Environment, error) {
+func (s *System[T]) Environment() (*environments.Environment, error) {
 	if s.builder.environment != nil {
 		return s.builder.environment, nil
 	}
@@ -42,7 +42,7 @@ func (s *System) Environment() (*environments.Environment, error) {
 	return s.builder.environment, err
 }
 
-func (s *System) Collection() (*collections.Collection, error) {
+func (s *System[T]) Collection() (*collections.Collection, error) {
 	if s.builder.collection != nil {
 		return s.builder.collection, nil
 	}