This looks amazing! Thank you for making such good documentation to get this thing going.
Glad if it is useful
Thanks!
Amazing work because I’m currently making the switch from Altium to Kicad. If I may ask:
In your Global Libraries dialog you have both the database library (kicad_dbl) and the schematic symbol libraries (kicad_sym) (and I guess footprint libraries as well).
Do the kicad_sym files need to be added to the Global Library dialog as well or can those be left out for the kicad_dbl to find them?
With AD we’ve been following the One Symbol / File approach, this doesn’t seem to be useful in Kicad because you’d need to add all of those to the Global Libraries if they need to be added.
Is it common to put the symbols for a group (e.g. Passives) into a single file? Or all schematic symbols? What would you recommend?
Thank you
Glad if it helps you to create your own DB.
In your Global Libraries dialog you have both the database library (kicad_dbl) and the schematic symbol libraries (kicad_sym) (and I guess footprint libraries as well).
Yea, as far as I have tested you need to add all the Symbol and Footprint libraries as your global libraries (I have not tested with local libraries). It is because your database will reference to those libraries.
Do the kicad_sym files need to be added to the Global Library dialog as well or can those be left out for the kicad_dbl to find them?
As far as I know, you need to add all symbol and footprint libraries that you want to reference to in your database. However, you can select that all the libraries except database library would be not visible, so this way when you will search for component in your project you will see only components from your database.
Is it common to put the symbols for a group (e.g. Passives) into a single file? Or all schematic symbols? What would you recommend?
I think it is common. Official KiCAD library have Device Symbol library where there is placed capacitors, resistors and other common symbols. I have separated passives into Psv_Resistors, Psv_Capacitors, Psv_Inductors and Psv_Other. This is because I like to add package to those symbols. I use separate symbols for 0402 resistors and 0603 resistors. I like this because this way I have more information on the schematics.
It more depends on how you like your schematics to look. I have worked with libraries where all the components are added into one library and after a while, when there are a lot of components, that library becomes quite messy.
I have separated my symbol libraries into:
- Diodes
- Transistors
- Active_Other (Diacs, Triacs etc.)
- Connectors
- Integrated_Circuits
- Modules
- Oscillators
- Switches
- Devices (LCDs, Buzzers, Microphones, Antennas etc.)
- Capacitors
- Resistors
- Inductors
- Passive_Other (Fuses etc.)
- PCB_Components (Testpoints, Mounting Holes etc.)
This seems to be working for me. Feel free if you want to do something similar. If you have any other questions I am glad to help
Thank you, great detailed response. I’ll try to implement it the same way.
Just wanted to give some feedback. I have successfully transferred our Altium library to a Kicad library. Also, the sym-lib-table and fp-lib-table files are generated automatically from the available files.
That’s pretty cool.
You don’t need separate symbols for 0402 and 0603. Just add field and put in symbol
See: the isolation working voltage is done using field. But with specified color and placement (autoplacement is disabled for this field).
Also, you may want to add marker field for SMD components
Glad it works for you
Yea, you are right, I just like to have all my symbols with the same fields and no additional fields, but thats just my internal symbol rules.
Great idea about component marking parameters
I’m not advanced enough yet to import a library but I can appreciate its usefulness. Eventually I will work with it for certain. I’m not sure if I’m just old but we used to call caps “Axial” and “Radial”. Not sure if that helps or if I just look like a jerk. Keep up the good work!
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
@Mantvis, first of all, thank you so much for your detailed posting!
I am confused about one thing. In this earlier posting (granted, for KiCAD7; now we are on KiCAD9!), @teletypeguy extensively discusses a JSON file which translates between KiCAD and the database. @craftyjon also discussed this file in his presentation at KiCon2023 in Europe (advance the video to 7:30). I don’t see any reference to such file in your posting. Has something changed from KiCAD7?
The *.kicad_dbl file mentioned above is the ‘database link’ file and defines how KiCad accesses and interacts with the database. It is written in JSON format (JavaScript Object Notation). Here is a useful link and further description - it is for macOS but the same principles apply for any platform and the format of the *.kidcad_dbl file is discussed.
Hi
I am also going to do the advanced digital design course and I noticed that XC7Z footprint/symbols arent in default kicad 7 libs… did you create your own for that course?
would have asked in the other thread but its locked
Hi,
Yes, I created the symbols and footprints for the course
Some were modified original kicad libs, others I created from scratch
Sure.
We’ve been using a DbLib in Altium for years. The table format is in fact very similar; I just had to create a new table based on the data we already had in there. The reason for that is that KiCad typically uses multiple parts per file for schematic symbols while we were using single part per file in Altium. That’s one of my pet peeves which is better in Altium because it enables nicer version control of parts. That was the easy part.
That’s the schema for the database:
USE [KicadLibrary]
GO
/****** Object: Table [dbo].[Parts] Script Date: 24.06.2025 08:20:45 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Parts](
[Ident] [nvarchar](32) NOT NULL,
[Symbols] [nvarchar](512) NULL,
[Footprints] [nvarchar](512) NULL,
[Description] [nvarchar](512) NULL,
[ValueA] [nvarchar](256) NULL,
[ValueB] [nvarchar](256) NULL,
[CheckedBy] [nvarchar](16) NULL,
[CheckedOn] [datetime] NULL,
[CreatedBy] [nvarchar](16) NULL,
[CreatedOn] [datetime] NULL,
[Datasheet1Uri] [nvarchar](256) NULL,
[Datasheet2Uri] [nvarchar](256) NULL,
[Datasheet3Uri] [nvarchar](256) NULL,
[Manufacturer1] [nvarchar](128) NULL,
[Manufacturer2] [nvarchar](128) NULL,
[Manufacturer3] [nvarchar](128) NULL,
[Manufacturer4] [nvarchar](128) NULL,
[Manufacturer5] [nvarchar](128) NULL,
[ManufacturerPartNumber1] [nvarchar](128) NULL,
[ManufacturerPartNumber2] [nvarchar](128) NULL,
[ManufacturerPartNumber3] [nvarchar](128) NULL,
[ManufacturerPartNumber4] [nvarchar](128) NULL,
[ManufacturerPartNumber5] [nvarchar](128) NULL,
[Package] [nvarchar](128) NULL,
[PackageGroup] [nvarchar](1) NULL,
CONSTRAINT [PK_Parts] PRIMARY KEY CLUSTERED
(
[Ident] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
The symbols and footprints can be converted to KiCad format automatically. For symbols, you will need to use the one file contains many parts methods because you will need to add the files to the library in Kicad (you cannot simply add the kicad_dbl file and expect it to find your symbols - this should be changed in Kicad). For footprints it was easier as it’s the same here, just the folders are named .pretty.
This is the C# code for converting your symbols and footprints to kicad format (we’re using the kicad-cli)
Console.WriteLine("Schematic Symbols");
foreach (var schLibFile in Directory.GetFiles(baseAltiumPathSch, "*.schlib", SearchOption.AllDirectories))
{
FileInfo fi = new FileInfo(schLibFile);
var pathAltium = fi.DirectoryName;
if (pathAltium == null)
{
throw new Exception("Invalid");
}
var pathKicad = pathAltium.Replace(baseAltiumPathSch, baseKicadPathSch);
var filenameKicad = fi.Name.Replace(".schlib", ".kicad_sym", true, CultureInfo.InvariantCulture);
var fullFilename = Path.Combine(pathKicad, filenameKicad);
Directory.CreateDirectory(pathKicad);
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = kicadCliExecutable;
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
var argumentsList = $"sym upgrade --output \"{fullFilename}\" \"{schLibFile}\"";
psi.Arguments = argumentsList;
Process process = new Process();
process.StartInfo = psi;
process.Start();
process.WaitForExit(10000);
if (process.ExitCode != 0)
{
Console.Write($"{process.ExitCode}");
Console.WriteLine(" " + process.StandardOutput.ReadToEnd());
Console.WriteLine(" " + process.StandardError.ReadToEnd());
}
}
From that you build the library file for Kicad:
// Build the sym-lib-table file
SNodeList libList = new SNodeList
{
Items = []
};
SExpression sexKicadSymLibTable = new SExpression("sym_lib_table", libList.Items);
libList.Items.Add(new SExpression("version", 7));
var dbLibEntry = new SNodeList
{
Items = []
};
dbLibEntry.Items.Add(new SExpression("name", "kicad_db"));
dbLibEntry.Items.Add(new SExpression("type", "Database"));
dbLibEntry.Items.Add(new SExpression("uri", "${KICAD8_SYMBOL_DIR}/kicad_db.kicad_dbl"));
dbLibEntry.Items.Add(new SExpression("options", ""));
dbLibEntry.Items.Add(new SExpression("descr", ""));
libList.Items.Add(new SExpression("lib", dbLibEntry.Items));
foreach (var file in Directory.GetFiles(baseKicadPathSch, "*.kicad_sym", SearchOption.TopDirectoryOnly))
{
FileInfo fi = new FileInfo(file);
var innerLib = new SNodeList
{
Items = []
};
innerLib.Items.Add(new SExpression("name", fi.Name.Replace(".kicad_sym", "")));
innerLib.Items.Add(new SExpression("type", "KiCad"));
innerLib.Items.Add(new SExpression("uri", fi.FullName.Replace("/", "\\")));
innerLib.Items.Add(new SExpression("options", ""));
innerLib.Items.Add(new SExpression("descr", ""));
innerLib.Items.Add(new SNodeList()
{
Items = new List<SNodeBase> { new SNodeAtom("hidden") }
});
libList.Items.Add(new SExpression("lib", innerLib.Items));
}
sexKicadSymLibTable.WriteToFile(kicadSymLibTable);
This is the code for the footprints
// Footprints, we need to handle the subfolders differently here
// Console.WriteLine("Footprints");
foreach (var pcbLibFile in Directory.GetFiles(baseAltiumPathPcb, "*.pcblib", SearchOption.AllDirectories))
{
// Get the first directory they are in, cannot go deeper than 1 folder
FileInfo fi = new FileInfo(pcbLibFile);
var filenameKicad = fi.Name.Replace(".pcblib", ".kicad_mod", true, CultureInfo.InvariantCulture);
var directories = pcbLibFile.Split(Path.DirectorySeparatorChar);
var directory = directories[3];
directory += ".pretty";
if (Directory.Exists(temporaryConversionFileName))
{
Directory.Delete(temporaryConversionFileName, true);
}
var folder = Path.Combine(baseKicadPathPcb, directory);
Directory.CreateDirectory(folder);
//var destinationFullFilename = Path.Combine(folder, filenameKicad);
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = kicadCliExecutable;
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
var argumentsList = $"fp upgrade --output \"{temporaryConversionFileName}\" \"{pcbLibFile}\"";
psi.Arguments = argumentsList;
Process process = new Process();
process.StartInfo = psi;
process.Start();
process.WaitForExit(10000);
if (process.ExitCode != 0)
{
Console.Write($"{process.ExitCode}");
Console.WriteLine(" " + process.StandardOutput.ReadToEnd());
Console.WriteLine(" " + process.StandardError.ReadToEnd());
continue;
}
// This has now created a library, but we need the file from inside that library
var innerFileName = Path.Combine(temporaryConversionFileName, filenameKicad);
var destinationFilename = Path.Combine(folder, filenameKicad);
File.Move(innerFileName, destinationFilename);
}
From that, you build the footprint library file for Kicad
SNodeList fbList = new SNodeList
{
Items = []
};
SExpression sexKicadFpLibTable = new SExpression("fp_lib_table", fbList.Items);
foreach (var dir in Directory.GetDirectories(baseKicadPathPcb, "*.pretty", SearchOption.TopDirectoryOnly))
{
DirectoryInfo di = new DirectoryInfo(dir);
var innerLib = new SNodeList
{
Items = []
};
innerLib.Items.Add(new SExpression("name", di.Name.Replace(".pretty", "")));
innerLib.Items.Add(new SExpression("type", "KiCad"));
innerLib.Items.Add(new SExpression("uri", di.FullName.Replace("/", "\\")));
innerLib.Items.Add(new SExpression("options", ""));
innerLib.Items.Add(new SExpression("descr", ""));
//innerLib.Items.Add(new SNodeList()
//{
// Items = new List<SNodeBase> { new SNodeAtom("hidden") }
//});
fbList.Items.Add(new SExpression("lib", innerLib.Items));
}
sexKicadFpLibTable.WriteToFile(kicadFpTable);
And here is the code that creates the table from the parts
List<Part> parts = new List<Part>();
// Build a dictionary which part can be found in which library (schematic symbols)
Dictionary<string, string> symLibLocations = new Dictionary<string, string>();
foreach (var kicadSymLibFile in Directory.GetFiles(@"A:\libs_kicad\SCH", "*.kicad_sym", SearchOption.TopDirectoryOnly))
{
// Load the symbols in that file
SExpression sexSymLibFile = new SExpression();
sexSymLibFile.LoadFromFile(kicadSymLibFile);
string symLibName = new FileInfo(kicadSymLibFile).Name.Replace(".kicad_sym", "");
foreach (var item in sexSymLibFile.Items.Where(d => d is SExpression && ((SExpression)d).Name == "symbol"))
{
var sItem = (SExpression)item;
var value = sItem.GetValue();
symLibLocations.Add(value, symLibName + ":" + value);
}
}
// Build a dictionary which part can be found in which library (footprints)
Dictionary<string, string> fpLibLocations = new Dictionary<string, string>();
foreach (var kicadFpLibDirectory in Directory.GetDirectories(@"A:\libs_kicad\PCB", "*.pretty", SearchOption.TopDirectoryOnly))
{
var libName = new DirectoryInfo(kicadFpLibDirectory).Name.Replace(".pretty", "");
foreach (var file in Directory.GetFiles(kicadFpLibDirectory, "*.kicad_mod", SearchOption.TopDirectoryOnly))
{
FileInfo fi = new FileInfo(file);
var fpName = fi.Name.Replace(".kicad_mod", "");
fpLibLocations.Add(fpName, libName + ":" + fpName);
}
}
foreach (var erpPart in erpArticles.Where(d=>!string.IsNullOrEmpty(d.Value.SchematicReference)))
{
var part = new Part();
part.Ident = erpPart.Key;
part.CreatedBy = erpPart.Value.CreatedBy;
part.CreatedOn = erpPart.Value.CreatedOn;
part.CheckedBy = erpPart.Value.CheckedBy;
part.CheckedOn = erpPart.Value.CheckedOn;
part.Datasheet1Uri = erpPart.Value.Datasheet1Uri;
part.Datasheet2Uri = erpPart.Value.Datasheet2Uri;
part.Datasheet3Uri = erpPart.Value.Datasheet3Uri;
part.Description = erpPart.Value.DescriptionLong;
if (symLibLocations.ContainsKey(erpPart.Value.SchematicReference))
{
part.Symbols = symLibLocations[erpPart.Value.SchematicReference];
}
else
{
Console.WriteLine($"{part.Ident}: Symbol {erpPart.Value.SchematicReference} nicht gefunden");
}
var footprints = new List<string>
{
(erpPart.Value.FootprintReference),
(erpPart.Value.FootprintReference2),
(erpPart.Value.FootprintReference3)
}.Where(d => !string.IsNullOrWhiteSpace(d));
List<string> foundFootprints = new List<string>();
foreach (var footprint in footprints)
{
if (fpLibLocations.TryGetValue(footprint, out var location))
{
foundFootprints.Add(location);
}
else
{
Console.WriteLine($"{part.Ident}: FP {footprint} nicht gefunden");
}
}
part.Footprints = string.Join(",", foundFootprints);
part.Manufacturer1 = erpPart.Value.Manufacturer1;
part.Manufacturer2 = erpPart.Value.Manufacturer2;
part.Manufacturer3 = erpPart.Value.Manufacturer3;
part.Manufacturer4 = erpPart.Value.Manufacturer4;
part.Manufacturer5 = erpPart.Value.Manufacturer5;
part.ManufacturerPartNumber1 = erpPart.Value.ManufacturerPartNumber1;
part.ManufacturerPartNumber2 = erpPart.Value.ManufacturerPartNumber2;
part.ManufacturerPartNumber3 = erpPart.Value.ManufacturerPartNumber3;
part.ManufacturerPartNumber4 = erpPart.Value.ManufacturerPartNumber4;
part.ManufacturerPartNumber5 = erpPart.Value.ManufacturerPartNumber5;
part.Package = erpPart.Value.Package;
part.PackageGroup = erpPart.Value.PackageGroup;
parts.Add(part);
}
using var kicadLibrary = new KicadLibraryContext();
kicadLibrary.Parts.RemoveRange(kicadLibrary.Parts);
kicadLibrary.Parts.AddRange(parts);
kicadLibrary.SaveChanges();
The whole thing is currently a proof on concept. We’re not using it in production right now but I could successfully place parts in Kicad and the footprints were tied in as well. It sure needs some fine tweaking if it’s going into production but I’d like to see some changes in Kicad before we’re actually making the switch:
I think I wrote about these in another post but in general I’d like to use the one part / file strategy and not have to add each symlib library file to the Kicad library manager. Just add the kicad_dbl file and you should be done.
I hope that helps; I know it’s a bit unstructured but it’s a proof-of-concept which worked quite fine. Certainly you’ll need to tie it to your requirements. The SExpression code and CParser code were both taken from GitHub - bobc/eakit: A tool to convert EAGLE(tm) CAD projects to KiCad.
Thanks everybody for this insightful discussion thread. I have a general question: I have quite a few KiCAD projects, some dating back to version 4. The components, especially passives, have a fairly consistent field structure. Is there any way to open an old project (assuming KiCAD successfully converts it to version 9) and then pick a component in that project and transfer it to the database? So far, our discussions have revolved around copying a component from the database to the schematic (after first setting up the database); how about the reverse, copying a component from the schematic to the database?
This topic was automatically closed after 30 days. New replies are no longer allowed.