diff --git a/src/reflect.zig b/src/reflect.zig
index ce25065..35c89e0 100644
--- a/src/reflect.zig
+++ b/src/reflect.zig
@@ -433,6 +433,15 @@ pub const Func = struct {
         try self.return_type.lookup(structs);
     }
 
+    fn hasAlloc(comptime self: Func) bool {
+        for (self.args) |arg| {
+            if (arg.underT() == std.mem.Allocator) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     fn reflect(
         comptime T: type,
         comptime kind: FuncKind,
@@ -870,6 +879,18 @@ pub const Struct = struct {
         return attrs;
     }
 
+    // Does the T has a well-formed deinit method?
+    fn _checkDeinit(comptime T: type, comptime self_T: type, isErr: bool) !void {
+        if (!isDecl(
+            T,
+            "deinit",
+            fn (_: *self_T, _: std.mem.Allocator) void,
+            isErr,
+        )) {
+            return error.StructAllocWrongDeinit;
+        }
+    }
+
     // Is the T a well-formed exception?
     fn _checkException(comptime T: type, isErr: bool) Error!void {
 
@@ -894,6 +915,13 @@ pub const Struct = struct {
         if (!isDecl(T, "get_message", fn (_: T) []const u8, isErr)) return err;
     }
 
+    // Has the API a deinit method?
+    pub fn hasDenit(comptime self: Struct) bool {
+        std.debug.assert(@inComptime());
+        Struct._checkDeinit(self.T, self.Self(), false) catch false;
+        return true;
+    }
+
     // Is the API an exception?
     pub fn isException(comptime self: Struct) bool {
         std.debug.assert(@inComptime());
@@ -1181,6 +1209,44 @@ pub const Struct = struct {
             }
         }
 
+        // check deinit
+        // only if at least one function has an allocator argument
+        var check_deinit = false;
+        if (has_constructor and constructor.hasAlloc()) {
+            check_deinit = true;
+        }
+        if (!check_deinit) {
+            for (getters) |getter| {
+                if (getter.hasAlloc()) {
+                    check_deinit = true;
+                    break;
+                }
+            }
+        }
+        if (!check_deinit) {
+            for (setters) |setter| {
+                if (setter.hasAlloc()) {
+                    check_deinit = true;
+                    break;
+                }
+            }
+        }
+        if (!check_deinit) {
+            for (methods) |method| {
+                if (method.hasAlloc()) {
+                    check_deinit = true;
+                    break;
+                }
+            }
+        }
+        if (check_deinit) {
+            if (self_T) |self| {
+                try Struct._checkDeinit(T, self, true);
+            } else {
+                try Struct._checkDeinit(T, T, true);
+            }
+        }
+
         // string tag
         var string_tag: bool = false;
         for (getters) |getter| {
@@ -1440,6 +1506,7 @@ const Error = error{
     StructExceptionWrongErrorSet,
     StructExceptionWrongInterface,
     StructExceptionDoesNotExist,
+    StructAllocWrongDeinit,
 
     // func errors
     FuncNoSelf,
@@ -1566,10 +1633,30 @@ const MyException = struct {
     pub fn get_message(_: MyException) []const u8 {
         return "";
     }
+    pub fn deinit(_: *MyException, _: std.mem.Allocator) void {}
 };
 const TestStructExceptionDoesNotExist = struct {
     pub const Exception = MyException;
 };
+const TestStructAllocNoDeinit = struct {
+    name: []const u8,
+    pub fn constructor(alloc: std.mem.Allocator, name: []const u8) TestStructAllocWrongDeinit {
+        const name_alloc = alloc.alloc(u8, name.len);
+        @memcpy(name_alloc, name);
+        return .{ .name = name_alloc };
+    }
+};
+const TestStructAllocWrongDeinit = struct {
+    name: []const u8,
+    pub fn constructor(alloc: std.mem.Allocator, name: []const u8) TestStructAllocWrongDeinit {
+        const name_alloc = alloc.alloc(u8, name.len);
+        @memcpy(name_alloc, name);
+        return .{ .name = name_alloc };
+    }
+    pub fn deinit(_: TestStructAllocWrongDeinit, _: std.mem.Allocator) void {
+        // should be a pointer
+    }
+};
 
 // funcs tests
 const TestFuncNoSelf = struct {
@@ -1700,6 +1787,14 @@ pub fn tests() !void {
         .{TestStructExceptionDoesNotExist},
         error.StructExceptionDoesNotExist,
     );
+    try ensureErr(
+        .{TestStructAllocNoDeinit},
+        error.StructAllocWrongDeinit,
+    );
+    try ensureErr(
+        .{TestStructAllocWrongDeinit},
+        error.StructAllocWrongDeinit,
+    );
 
     // funcs checks
     try ensureErr(
diff --git a/src/tests/proto_test.zig b/src/tests/proto_test.zig
index bc5b274..1a90a02 100644
--- a/src/tests/proto_test.zig
+++ b/src/tests/proto_test.zig
@@ -82,6 +82,10 @@ const Person = struct {
     pub fn get_symbol_toStringTag(_: Person) []const u8 {
         return "MyPerson";
     }
+
+    pub fn deinit(self: *Person, alloc: std.mem.Allocator) void {
+        alloc.free(self.last_name);
+    }
 };
 
 const User = struct {
@@ -103,6 +107,10 @@ const User = struct {
     pub fn get_role(self: User) u8 {
         return self.role;
     }
+
+    pub fn deinit(self: *User, alloc: std.mem.Allocator) void {
+        self.proto.deinit(alloc);
+    }
 };
 
 const PersonPtr = struct {
@@ -126,6 +134,10 @@ const PersonPtr = struct {
         @memcpy(name_alloc, name);
         self.name = name_alloc;
     }
+
+    pub fn deinit(self: *PersonPtr, alloc: std.mem.Allocator) void {
+        alloc.free(self.name);
+    }
 };
 
 const UserForContainer = struct {
@@ -174,6 +186,10 @@ const UserContainer = struct {
     pub fn _roleVal(self: UserForContainer) u8 {
         return self.role;
     }
+
+    pub fn deinit(self: *UserForContainer, alloc: std.mem.Allocator) void {
+        self.proto.deinit(alloc);
+    }
 };
 
 const PersonProtoCast = struct {
@@ -192,6 +208,10 @@ const PersonProtoCast = struct {
     pub fn get_name(self: PersonProtoCast) []const u8 {
         return self.first_name;
     }
+
+    pub fn deinit(self: *PersonProtoCast, alloc: std.mem.Allocator) void {
+        alloc.free(self.first_name);
+    }
 };
 
 const UserProtoCast = struct {
@@ -202,6 +222,10 @@ const UserProtoCast = struct {
     pub fn constructor(alloc: std.mem.Allocator, first_name: []u8) UserProtoCast {
         return .{ .not_proto = PersonProtoCast.constructor(alloc, first_name) };
     }
+
+    pub fn deinit(self: *UserProtoCast, alloc: std.mem.Allocator) void {
+        self.not_proto.deinit(alloc);
+    }
 };
 
 // generate API, comptime
diff --git a/src/tests/types_complex_test.zig b/src/tests/types_complex_test.zig
index 398a38e..76f42fc 100644
--- a/src/tests/types_complex_test.zig
+++ b/src/tests/types_complex_test.zig
@@ -23,6 +23,10 @@ const MyList = struct {
     pub fn _symbol_iterator(self: MyList) MyIterable {
         return MyIterable.init(self.items);
     }
+
+    pub fn deinit(self: *MyList, alloc: std.mem.Allocator) void {
+        alloc.free(self.items);
+    }
 };
 
 const MyVariadic = struct {
@@ -49,6 +53,8 @@ const MyVariadic = struct {
     pub fn _empty(_: MyVariadic, _: ?VariadicBool) bool {
         return true;
     }
+
+    pub fn deinit(_: *MyVariadic, _: std.mem.Allocator) void {}
 };
 
 const MyErrorUnion = struct {
@@ -111,6 +117,8 @@ pub const MyException = struct {
             ErrorSet.MyCustomError => errorStrings(0),
         };
     }
+
+    pub fn deinit(_: *MyException, _: std.mem.Allocator) void {}
 };
 
 const MyTypeWithException = struct {
diff --git a/src/tests/types_native_test.zig b/src/tests/types_native_test.zig
index a43b761..0e7bdf9 100644
--- a/src/tests/types_native_test.zig
+++ b/src/tests/types_native_test.zig
@@ -25,6 +25,10 @@ const Brand = struct {
         @memcpy(name_alloc, name);
         self.name = name_alloc;
     }
+
+    pub fn deinit(self: *Brand, alloc: std.mem.Allocator) void {
+        alloc.free(self.name);
+    }
 };
 
 const Car = struct {
@@ -118,6 +122,10 @@ const Car = struct {
     pub fn _getBrandPtr(self: Car) *Brand {
         return self.get_brandPtr();
     }
+
+    pub fn deinit(self: *Car, alloc: std.mem.Allocator) void {
+        alloc.destroy(self.brand_ptr);
+    }
 };
 
 // Native types with nested APIs